...
 
Commits (15)
...@@ -14,3 +14,9 @@ cythonModules/build/ ...@@ -14,3 +14,9 @@ cythonModules/build/
*.pyd *.pyd
*.html *.html
*.pkl
chemometrics/Assignments.txt
chemometrics/Data.txt
import numpy as np
import cv2
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import DBSCAN
from scipy import spatial
from itertools import combinations
from random import sample
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
from gepard.analysis.particleContainer import ParticleContainer
from gepard.analysis import particleAndMeasurement as pm
from methods import SubsamplingMethod
def get_pca(data: np.ndarray, numComp: int = 2) -> np.ndarray:
try:
standardizedData = StandardScaler().fit_transform(data.copy())
except ValueError:
print('first standardscaler attempt failed, retrying..')
print('datashape', data.shape)
print('unique:', np.unique(data))
raise
pca = PCA(n_components=numComp)
princComp: np.ndarray = pca.fit_transform(np.transpose(standardizedData))
return princComp
def do_DBSCAN_clustering(data: np.ndarray, eps: float = 0.1, min_samples: int = 10) -> tuple:
"""
Does DBSCAN clustering and finds noisy data
:param data: The input array
:param eps:
:param min_samples:
:return: Cluster labels for each point in the dataset given to fit(). Noisy samples are given the label -1.
"""
assert data.shape[1] == 2
standardizedData = StandardScaler().fit_transform(data)
db = DBSCAN(eps=eps, min_samples=min_samples).fit(standardizedData)
return db.labels_, db.core_sample_indices_
def get_n_points_closest_to_point(points: np.ndarray, n: int, refPoint: np.ndarray) -> list:
"""
Returns a list with indices of n points that are closest to the indicated refPoint
:param points: np.ndarray, cols: x, y, rows: individual points
:param n: number of points to return
:param refPoint: np.array([x, y]) of reference point
:return: list of point indices
"""
distancesToPoints: np.ndarray = np.linalg.norm(points - refPoint, axis=1)
sortedIndices = np.argsort(distancesToPoints)
return list(sortedIndices[:n])
class ChemometricSubsampling(SubsamplingMethod):
def __init__(self, particleContainer: ParticleContainer, desiredFraction: float):
super(ChemometricSubsampling, self).__init__(particleContainer, desiredFraction)
@property
def label(self) -> str:
return 'Chemometric Selection'
def apply_subsampling_method(self) -> list:
vectors: np.ndarray = self._get_particle_featurematrix()
try:
princComps: np.ndarray = get_pca(vectors)
except ValueError:
print('numParticles:', len(self.particleContainer.particles))
print('input featurematrix shape', vectors.shape)
clusterLabels, coreIndices = do_DBSCAN_clustering(princComps)
indices: list = self._get_indices_from_clusterLabels(princComps, clusterLabels, coreIndices)
selectedParticles: list = []
for particle in self.particleContainer.particles:
if particle.index in indices:
selectedParticles.append(particle)
return selectedParticles
def _get_particle_featurematrix(self) -> np.ndarray:
"""
:return: np.ndarray, numRows: Features, numCols: Particles
"""
vectors: list = []
for particle in self.particleContainer.particles:
extractor: FeatureExtractor = FeatureExtractor(particle)
vectors.append(extractor.get_characteristic_vector())
vectors: np.ndarray = np.transpose(np.array(vectors))
assert vectors.shape == (11, len(self.particleContainer.particles)), f'wrong featureMat-shape: {vectors.shape}'
return vectors
def equals(self, otherMethod) -> bool:
equals: bool = False
if type(otherMethod) == ChemometricSubsampling and otherMethod.fraction == self.fraction:
equals = True
return equals
def _get_indices_from_clusterLabels(self, points: np.ndarray, labels: np.ndarray, centerIndices: np.ndarray) -> list:
indices: list = []
allIndices: np.ndarray = np.arange(len(labels))
numPointsPerCluster: dict = self._get_numPoints_per_cluster(labels)
for clusterIndex in set(labels):
indToAppend: list = []
nPoints: int = int(numPointsPerCluster[clusterIndex])
indicesInCluster: np.ndarray = allIndices[labels == clusterIndex]
if clusterIndex == -1:
for ind in sample(list(indicesInCluster), nPoints):
# assert ind not in indices
indices.append(ind)
else:
clusterPoints: np.ndarray = points[indicesInCluster]
centerPoint: np.ndarray = np.mean(clusterPoints, axis=0)
indicesToSelect: list = get_n_points_closest_to_point(clusterPoints, nPoints, centerPoint)
for ind in indicesToSelect:
origInd = indicesInCluster[ind]
indices.append(origInd)
assert len(set(indices)) == len(indices), f'The calculated indices contain duplicates, ' \
f'num duplicates: {len(indices) - len(set(indices))}'
return indices
def _get_numPoints_per_cluster(self, labels: np.ndarray, noiseAmpFactor: float = 5) -> dict:
"""
MP Particles are expected to be the minority of all particles. So, if datapoints were classified as noise
(i.e., label = -1), it is likely that MP is in there. The abundancy of points taken from the noise is multiplied
by the noiseAmpFactor
:param labels:
:param noiseAmpFactor:
:return: A dictionary with keys = cluster index (i.e., label) and value = number of points to take from that
"""
pointsPerCluster: dict = {}
if type(labels) != np.ndarray:
labels = np.array(labels)
individualLabels: set = set(labels)
numPointsToSelect = round(len(labels) * self.fraction)
if numPointsToSelect == 0:
numPointsToSelect = 1
numNoisePoints = len(labels[labels == -1])
numClusteredPoints = len(labels) - numNoisePoints
# # get max noiseAmpFactor
if noiseAmpFactor > 1/self.fraction:
noiseAmpFactor = 1/self.fraction
numAmpPoints = numClusteredPoints + numNoisePoints*noiseAmpFactor
fractionPerCluster = np.clip(numPointsToSelect / numAmpPoints, 0.0, 1.0)
tooFewPoints = numPointsToSelect < len(individualLabels)
totalPointsAdded = 0
for ind in individualLabels:
if ind > -1:
if not tooFewPoints:
pointsToAdd = round(fractionPerCluster * len(labels[labels == ind]))
else:
pointsToAdd = 1 if totalPointsAdded < numPointsToSelect else 0
pointsPerCluster[ind] = pointsToAdd
totalPointsAdded += pointsToAdd
# fill up the rest with noisePoints
if numNoisePoints > 0:
diff: float = np.clip(numPointsToSelect - totalPointsAdded, 0, numNoisePoints)
pointsPerCluster[-1] = diff
totalPointsAdded += diff
# just in case too many points were selected (due to rounding errors), keep on deleting until it matches
while totalPointsAdded > numPointsToSelect:
indexWithHighestCount = None
maxCount = 0
for index in pointsPerCluster.values():
if pointsPerCluster[index] > maxCount:
maxCount = pointsPerCluster[index]
indexWithHighestCount = index
pointsPerCluster[indexWithHighestCount] -= 1
totalPointsAdded -= 1
if not abs(totalPointsAdded - numPointsToSelect) <= 1:
print('error')
# assert abs(totalPointsAdded - numPointsToSelect) <= 1
for clusterIndex in pointsPerCluster.keys():
assert 0 <= pointsPerCluster[clusterIndex] <= len(labels[labels == clusterIndex])
return pointsPerCluster
class FeatureExtractor(object):
def __init__(self, particle: pm.Particle):
super(FeatureExtractor, self).__init__()
self.particle: pm.Particle = particle
def get_characteristic_vector(self) -> np.ndarray:
log_hu: np.ndarray = self._get_log_hu_moments()
color: np.ndarray = self._get_color_hash(self.particle.color, desiredLength=4)
vector: np.ndarray = np.hstack((log_hu, color))
if len(vector) != 11:
print('error')
assert len(vector) == 7 + 4, f'wrong feature vector: {vector} with shape: {vector.shape}'
return vector
def _get_log_hu_moments(self) -> np.ndarray:
moments: dict = cv2.moments(self.particle.contour)
resultMoments: np.ndarray = np.zeros((7, 1))
for index, mom in enumerate(cv2.HuMoments(moments)):
if mom != 0:
resultMoments[index] = -1 * np.copysign(1.0, mom) * np.log10(abs(mom))
else:
resultMoments[index] = 0
return resultMoments[:, 0]
def _get_color_hash(self, color: str, desiredLength: int = 4) -> np.ndarray:
colorArray: list = [int(i) for i in str(abs(hash(color)))[:desiredLength]]
return np.transpose(np.array(colorArray))
This diff is collapsed.
import matplotlib.pyplot as plt
import numpy as np
from random import sample
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
import pickle
import time
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
from gepard import dataset
from gepard.analysis.particleContainer import ParticleContainer
from input_output import get_pkls_from_directory
from chemometricMethods import get_log_hu_moments, get_color_index, get_pca, get_characteristic_vector
from evaluation import is_MP_particle
def test_classification_models(dataset: tuple) -> None:
names = ["RandomForestClassifier", "NeuralNetClassifier"]
classifiers = [
RandomForestClassifier(n_estimators=1000),
MLPClassifier(alpha=1, max_iter=1000)]
t0 = time.time()
# preprocess dataset, split into training and test part
X, y = dataset
X = StandardScaler().fit_transform(X)
X_train, X_test, y_train, y_test = \
train_test_split(X, y, test_size=.3, random_state=42)
print(f'prepocessng finished after {round(time.time()-t0, 2)} seconds')
# iterate over classifiers
for name, clf in zip(names, classifiers):
t0 = time.time()
clf.fit(X_train, y_train)
print(f'fitting {name} took {round(time.time()-t0, 2)} seconds')
t0 = time.time()
score = clf.score(X_test, y_test)
with open(f'{name}, score {round(score, 2)}.pkl', "wb") as fp:
pickle.dump(clf, fp, protocol=-1)
y_predicted = clf.predict(X_test)
print(f'finished getting score and prediction after {round(time.time() - t0, 2)} seconds')
errors: dict = {int(k): 0 for k in np.unique(y_test)}
for j in range(len(y_predicted)):
if y_test[j] != y_predicted[j]:
errors[y_test[j]] += 1
print(f'{name} with test size {len(y_test)} has score {round(score, 2)}, errors: {errors}')
if __name__ == '__main__':
recreateNew: bool = True
if recreateNew:
pklsInFolders: dict = get_pkls_from_directory(r'C:\Users\xbrjos\Desktop\temp MP\NewDatasets')
X: list = []
y: list = []
counter = 0
for folder in pklsInFolders.keys():
for pklPath in pklsInFolders[folder]:
if counter < 100:
dset: dataset.DataSet = dataset.loadData(pklPath)
print('loaded', dset.name)
partContainer: ParticleContainer = dset.particleContainer
for particle in partContainer.particles:
features: np.ndarray = get_characteristic_vector(particle)
# features: list = [abs(i) for i in get_log_hu_moments(particle.contour)]
# features.append(get_color_index(particle.color))
X.append(features)
y.append(int(is_MP_particle(particle)))
counter += 1
X: np.ndarray = np.array(X)
y: np.ndarray = np.array(y)
MPindices: np.ndarray = np.where(y == 1)[0]
nonMPindices: np.ndarray = np.where(y == 0)[0]
nonMPindices: list = sample(list(nonMPindices), len(MPindices))
X_MP: list = list(X[MPindices])
y_MP: list = list(y[MPindices])
X_nonMP: list = list(X[nonMPindices])
y_nonMP: list = list(y[nonMPindices])
assert set(y_MP) == {1}
assert set(y_nonMP) == {0}
assert len(X_MP) == len(X_nonMP) == len(y_MP) == len(y_nonMP)
X_equalized: np.ndarray = np.array(X_MP + X_nonMP)
y_equalized: np.ndarray = np.array(y_MP + y_nonMP)
dset: tuple = (X_equalized, y_equalized)
with open('particleClassificaion.pkl', "wb") as fp:
pickle.dump(dset, fp, protocol=-1)
else:
with open('particleClassificaion.pkl', "rb") as fp:
dset: tuple = pickle.load(fp)
X, y = dset
# np.savetxt('Data.txt', X)
# np.savetxt('Assignments.txt', y)
# princComps = get_pca(X.transpose(), numComp=2)
#
# plt.scatter(princComps[:, 0], princComps[:, 1])
# print(X_equalized.shape)
# X: np.ndarray = SelectKBest(chi2, k=5).fit_transform(X, y)
# print(X_equalized.shape)
test_classification_models((X, y))
import numpy as np
cimport numpy as np
cimport numpy.random
cimport cython
DTYPE = np.float
ctypedef np.int32_t INT32_t
cdef get_random_topleft(double maxDist, double maxAngle, double radius, double boxSize):
cdef double angle, dist, x, y
cdef np.ndarray[INT32_t, ndim=1] newTopLeft
dist = np.random.rand() * maxDist
angle = np.random.rand() * maxAngle
newTopLeft = np.empty(2, dtype=np.int32)
x = dist*np.cos(angle) + radius - boxSize/2
y = dist*np.sin(angle) + radius - boxSize/2
newTopLeft[0] = np.int32(np.round(x))
newTopLeft[1] = np.int32(np.round(y))
return newTopLeft
def get_random_topLefts(int numBoxes, double boxSize, double radius, double maxAngle, int seed=1337, int maxTries=50):
cdef np.ndarray[INT32_t, ndim=2] topLefts
cdef np.ndarray[INT32_t, ndim=1] newTopLeft
cdef double maxDist
cdef int outerCounter, counter, x, y, i, j, diffX, diffY, successfullyAdded
cdef bint validSolutionFound, boxOverlaps
np.random.seed(seed)
maxDist = radius - np.sqrt((boxSize/2)**2 + (boxSize/2)**2)
outerCounter = 0
validSolutionFound = False
while not validSolutionFound and outerCounter < maxTries:
successfullyAdded = 0
topLefts = np.empty((numBoxes, 2), dtype=np.int32)
for i in range(numBoxes):
if i == 0:
topLefts[0, :] = get_random_topleft(maxDist, maxAngle, radius, boxSize)
successfullyAdded += 1
else:
counter = 0
while counter < 50:
newTopLeft = get_random_topleft(maxDist, maxAngle, radius, boxSize)
boxOverlaps = False
for j in range(i):
diffX = abs(np.float(newTopLeft[0] - np.float(topLefts[j, 0])))
diffY = abs(np.float(newTopLeft[1] - np.float(topLefts[j, 1])))
if diffX < boxSize and diffY < boxSize:
boxOverlaps = True
break
if boxOverlaps:
counter += 1
else:
topLefts[i, :] = newTopLeft
successfullyAdded += 1
break
if successfullyAdded == numBoxes:
validSolutionFound = True
else:
outerCounter += 1
return validSolutionFound, topLefts
\ No newline at end of file
...@@ -9,10 +9,18 @@ if len(sys.argv) == 1: ...@@ -9,10 +9,18 @@ if len(sys.argv) == 1:
sys.argv.append("build_ext") sys.argv.append("build_ext")
sys.argv.append("--inplace") sys.argv.append("--inplace")
ext = Extension("rotateContour", ["rotateContour.pyx"], extra_compile_args=['-O3'],) # ext = Extension("rotateContour", ["rotateContour.pyx"], extra_compile_args=['-O3'],)
# setup(
# name="rotate contour around reference point",
# ext_modules=cythonize([ext], annotate=True), # accepts a glob pattern
# include_dirs=[np.get_include()]
# )
# ext = Extension("getRandomTopLefts", ["getRandomTopLefts.pyx"], extra_compile_args=['-O3'],)
setup( setup(
name="rotate contour around reference point", name="get a given number of random topLefts",
ext_modules=cythonize([ext], annotate=True), # accepts a glob pattern ext_modules=cythonize("randoms.pyx", annotate=True), # accepts a glob pattern
include_dirs=[np.get_include()] include_dirs=[np.get_include()]
) )
\ No newline at end of file
...@@ -2,23 +2,28 @@ import copy ...@@ -2,23 +2,28 @@ import copy
import numpy as np import numpy as np
import sys import sys
sys.path.append("C://Users//xbrjos//Desktop//Python") sys.path.append("C://Users//xbrjos//Desktop//Python")
from gepard import dataset
from gepard.analysis.particleContainer import ParticleContainer from gepard.analysis.particleContainer import ParticleContainer
from cythonModules import rotateContour from cythonModules import rotateContour
from helpers import get_filterDimensions_from_dataset, get_center_from_filter_dimensions, convert_length_to_pixels
class ParticleVariations(object): class ParticleVariations(object):
def __init__(self, particleContainer: ParticleContainer, numVariations: int = 10) -> None: def __init__(self, dataset: dataset.DataSet, numVariations: int = 10) -> None:
super(ParticleVariations, self).__init__() super(ParticleVariations, self).__init__()
self.origParticleContainer = particleContainer self.dataset: dataset.DataSet = dataset
self.origParticleContainer: ParticleContainer = self.dataset.particleContainer
self.numVariations = numVariations self.numVariations = numVariations
def get_particleContainer_variations(self) -> ParticleContainer: def get_particleContainer_variations(self) -> ParticleContainer:
if self.numVariations > 0: if self.numVariations > 0:
offset, diameter, [width, height] = get_filterDimensions_from_dataset(self.dataset)
diameter: float = convert_length_to_pixels(self.dataset, diameter)
offset: tuple = convert_length_to_pixels(self.dataset, offset[0]), \
convert_length_to_pixels(self.dataset, offset[1])
center: np.ndarray = get_center_from_filter_dimensions(offset, diameter)
partContainer: ParticleContainer = self.origParticleContainer partContainer: ParticleContainer = self.origParticleContainer
contours: list = partContainer.getParticleContours()
center: tuple = round(np.mean(contours[:][0][0])),\
round(np.mean(contours[:][0][1]))
center: np.ndarray = np.array(center, dtype=np.int32)
angles = self._get_angles() angles = self._get_angles()
for i in range(self.numVariations): for i in range(self.numVariations):
if i > 0: if i > 0:
......
This diff is collapsed.
This diff is collapsed.
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np
from evaluation import TotalResults
def get_error_vs_frac_plot(totalResults: TotalResults, attributes: list = [], methods: list = [],
standarddevs=True, fill=True) -> Figure:
if len(attributes) == 0 and len(methods) != 0:
attributes = [[]]*len(methods)
elif len(methods) == 0 and len(attributes) != 0:
methods = [[]]*len(attributes)
assert len(attributes) == len(methods)
fig: Figure = plt.figure(figsize=(10, 5))
numRows: int = 1
numCols: int = 1
if len(attributes) == 0:
attributes = methods = [[]]
elif len(attributes) <= 2:
numCols = len(attributes)
else:
numRows = 2
numCols = np.ceil(len(attributes)/numRows)
index = 0
for attrs, meths in zip(attributes, methods):
ax = fig.add_subplot(numRows, numCols, index + 1)
errorPerFraction: dict = totalResults.get_error_vs_fraction_data(attributes=attrs,
methods=meths)
for methodLabel in errorPerFraction.keys():
errorDict: dict = errorPerFraction[methodLabel]
fractions: list = list(errorDict.keys())
errors: np.ndarray = np.array([errorDict[fraction][0] for fraction in fractions])
stdevs: np.ndarray = np.array([errorDict[fraction][1] for fraction in fractions])
if not standarddevs:
ax.plot(fractions, errors, label=methodLabel, marker='s')
else:
line = ax.errorbar(fractions, errors, stdevs, label=methodLabel, marker='s', capsize=5)
if fill:
color = line[0].get_color()
ax.fill_between(fractions, errors-stdevs, errors+stdevs, alpha=0.2, facecolor=color)
title: str = ''
if len(attrs) > 0:
title = ', '.join(attr for attr in attrs)
print('title is', title)
ax.set_title(title, fontSize=15)
ax.set_xscale('log')
ax.set_xlabel('measured fraction', fontsize=12)
ax.set_ylabel('mpCountError (%)', fontsize=12)
ax.set_xlim([0.9 * min(fractions), 1.05])
ax.set_ylim([0, 100])
ax.legend()
index += 1
fig.tight_layout()
return fig
# def get_grouped_spectra_plot(groupedSpectra: list, wavenumbers=None) -> matplotlib.figure.Figure:
# if wavenumbers is None:
# wavenumbers = np.arange(len(groupedSpectra[0][0]))
#
# numLabels = len(groupedSpectra)
# numRows = numLabels // 3
# numCols = np.ceil(numLabels / numRows)
# fig: matplotlib.figure.Figure = plt.figure()
#
# for index, specs in enumerate(groupedSpectra):
# ax = fig.add_subplot(numRows, numCols, index + 1)
# for spec in specs:
# ax.plot(wavenumbers, spec)
# ax.set_title(f'{len(specs)} spectra of label {index + 1}')
#
# return fig
\ No newline at end of file
...@@ -6,7 +6,7 @@ import gepard ...@@ -6,7 +6,7 @@ import gepard
from gepard import dataset from gepard import dataset
import helpers import helpers
from cythonModules import rotateContour as rc from cythonModules import rotateContour as rc
from evaluation import is_MP_particle
class FilterView(QtWidgets.QGraphicsView): class FilterView(QtWidgets.QGraphicsView):
...@@ -49,12 +49,11 @@ class FilterView(QtWidgets.QGraphicsView): ...@@ -49,12 +49,11 @@ class FilterView(QtWidgets.QGraphicsView):
self._update_particle_contours() self._update_particle_contours()
self._fit_to_window() self._fit_to_window()
@helpers.timingDecorator
def update_rotation(self, newRotation: int) -> None: def update_rotation(self, newRotation: int) -> None:
if newRotation != self.rotation: if newRotation != self.rotation:
angle: float = np.float(newRotation-self.rotation) angle: float = np.float(newRotation-self.rotation)
center: np.ndarray = np.array([self.filter.circleOffset[0] + self.filter.diameter/2, center: np.ndarray = helpers.get_center_from_filter_dimensions(self.filter.circleOffset,
self.filter.circleOffset[1] + self.filter.diameter/2], dtype=np.int32) self.filter.diameter)
for particle in self.dataset.particleContainer.particles: for particle in self.dataset.particleContainer.particles:
particle.contour = rc.rotate_contour_around_point(particle.contour, center, angle) particle.contour = rc.rotate_contour_around_point(particle.contour, center, angle)
...@@ -62,12 +61,11 @@ class FilterView(QtWidgets.QGraphicsView): ...@@ -62,12 +61,11 @@ class FilterView(QtWidgets.QGraphicsView):
self._update_particle_contours() self._update_particle_contours()
self.rotation = newRotation self.rotation = newRotation
@helpers.timingDecorator
def _update_particle_contours(self) -> None: def _update_particle_contours(self) -> None:
self._remove_particle_contours() self._remove_particle_contours()
if self.dataset is not None: if self.dataset is not None:
for particle in self.dataset.particleContainer.particles: for particle in self.dataset.particleContainer.particles:
newContour: ParticleContour = ParticleContour(particle.contour) newContour: ParticleContour = ParticleContour(particle.contour, is_MP_particle(particle))
self.scene().addItem(newContour) self.scene().addItem(newContour)
self.contourItems.append(newContour) self.contourItems.append(newContour)
...@@ -169,12 +167,13 @@ class MeasureBoxGraphItem(QtWidgets.QGraphicsItem): ...@@ -169,12 +167,13 @@ class MeasureBoxGraphItem(QtWidgets.QGraphicsItem):
class ParticleContour(QtWidgets.QGraphicsItem): class ParticleContour(QtWidgets.QGraphicsItem):
def __init__(self, contourData, pos=(0, 0)) -> None: def __init__(self, contourData, isMP: bool = False, pos: tuple = (0, 0)) -> None:
super(ParticleContour, self).__init__() super(ParticleContour, self).__init__()
self.setZValue(1) self.setZValue(1)
self.setPos(pos[0], pos[1]) self.setPos(pos[0], pos[1])
self.brect: QtCore.QRectF = QtCore.QRectF(0, 0, 1, 1) self.brect: QtCore.QRectF = QtCore.QRectF(0, 0, 1, 1)
self.isMP: bool = isMP
self.isMeasured: bool = False # Wether the particle overlaps with a measuring box or nt self.isMeasured: bool = False # Wether the particle overlaps with a measuring box or nt
self.contourData = contourData self.contourData = contourData
self.polygon = None self.polygon = None
...@@ -201,11 +200,13 @@ class ParticleContour(QtWidgets.QGraphicsItem): ...@@ -201,11 +200,13 @@ class ParticleContour(QtWidgets.QGraphicsItem):
def paint(self, painter, option, widget) -> None: def paint(self, painter, option, widget) -> None:
if self.polygon is not None: if self.polygon is not None:
if self.isMeasured: if self.isMP:
painter.setPen(QtCore.Qt.darkRed) painter.setPen(QtCore.Qt.darkRed)
painter.setBrush(QtCore.Qt.red) painter.setBrush(QtCore.Qt.red)
else: else:
painter.setPen(QtCore.Qt.darkCyan) painter.setPen(QtCore.Qt.darkBlue)
painter.setBrush(QtCore.Qt.cyan) painter.setBrush(QtCore.Qt.blue)
painter.setOpacity(1 if self.isMeasured else 0.2)
painter.drawPolygon(self.polygon) painter.drawPolygon(self.polygon)
from PyQt5 import QtWidgets from PyQt5 import QtWidgets, QtCore
import sys import sys
sys.path.append("C://Users//xbrjos//Desktop//Python") sys.path.append("C://Users//xbrjos//Desktop//Python")
import gepard import gepard
from gepard import dataset from gepard import dataset
from gui.filterView import FilterView from gui.filterView import FilterView
from gui.measureModes import MeasureMode, CrossBoxMode, CrossBoxesControls, SpiralBoxMode from gui.measureModes import *
import helpers import helpers
from evaluation import SubsamplingResult
class MainView(QtWidgets.QWidget): class MainView(QtWidgets.QWidget):
...@@ -30,7 +31,7 @@ class MainView(QtWidgets.QWidget): ...@@ -30,7 +31,7 @@ class MainView(QtWidgets.QWidget):
self.rotationSpinBox.setMaximum(359) self.rotationSpinBox.setMaximum(359)
self.rotationSpinBox.setValue(0) self.rotationSpinBox.setValue(0)
self.rotationSpinBox.setMaximumWidth(50) self.rotationSpinBox.setMaximumWidth(50)
self.rotationSpinBox.valueChanged.connect(self._update_fiter_rotation) self.rotationSpinBox.valueChanged.connect(self._update_filter_rotation)
self.controlGroup = QtWidgets.QGroupBox() self.controlGroup = QtWidgets.QGroupBox()
self.controlGroupLayout = QtWidgets.QHBoxLayout() self.controlGroupLayout = QtWidgets.QHBoxLayout()
...@@ -44,17 +45,29 @@ class MainView(QtWidgets.QWidget): ...@@ -44,17 +45,29 @@ class MainView(QtWidgets.QWidget):
self.controlGroupLayout.addWidget(self.activeModeControl) self.controlGroupLayout.addWidget(self.activeModeControl)
self.controlGroupLayout.addStretch() self.controlGroupLayout.addStretch()
self.infoWidget: SampleInfoWidget = SampleInfoWidget()
self.layout.addWidget(self.controlGroup) self.layout.addWidget(self.controlGroup)
self.layout.addWidget(self.infoWidget)
self.filterView = FilterView() self.filterView = FilterView()
self.layout.addWidget(self.filterView) self.layout.addWidget(self.filterView)
self._add_measure_modes() self._add_measure_modes()
self._switch_to_default_mode() self._switch_to_default_mode()
def _add_measure_modes(self) -> None: def _add_measure_modes(self) -> None:
self.measureModes['spiralSelection'] = SpiralBoxMode(self.filterView) self.measureModes['Random Particle Selection'] = RandomMeasureMode(self.filterView)
self.measureModes['crossSelection'] = CrossBoxMode(self.filterView) self.measureModes['Spiral Box Selection'] = SpiralBoxMode(self.filterView)
self.modeSelector.addItem('spiralSelection') self.measureModes['Cross Box Selection'] = CrossBoxMode(self.filterView)
self.modeSelector.addItem('crossSelection') self.measureModes['Random Box Selection'] = RandomBoxMode(self.filterView)
self.measureModes['Quarter Random Box Selection'] = QuarterRandomBoxMode(self.filterView)
self.modeSelector.addItem('Random Particle Selection')
self.modeSelector.addItem('Spiral Box Selection')
self.modeSelector.addItem('Cross Box Selection')
self.modeSelector.addItem('Random Box Selection')
self.modeSelector.addItem('Quarter Random Box Selection')
for mode in self.measureModes.values():
mode.updatedResult.connect(self.infoWidget.update_results)
def _switch_to_default_mode(self) -> None: def _switch_to_default_mode(self) -> None:
modes: list = list(self.measureModes.keys()) modes: list = list(self.measureModes.keys())
...@@ -76,7 +89,6 @@ class MainView(QtWidgets.QWidget): ...@@ -76,7 +89,6 @@ class MainView(QtWidgets.QWidget):
self.activeMode.update_measure_viewItems() self.activeMode.update_measure_viewItems()
@helpers.timingDecorator
def _load_dataset(self) -> None: def _load_dataset(self) -> None:
fname = QtWidgets.QFileDialog.getOpenFileName(self, 'Select .pkl file', filter='pkl file (*.pkl)') fname = QtWidgets.QFileDialog.getOpenFileName(self, 'Select .pkl file', filter='pkl file (*.pkl)')
if fname[0] != '': if fname[0] != '':
...@@ -96,20 +108,46 @@ class MainView(QtWidgets.QWidget): ...@@ -96,20 +108,46 @@ class MainView(QtWidgets.QWidget):
self.filterView.filter.update_filterSize(width, height, diameter, (offsetx, offsety)) self.filterView.filter.update_filterSize(width, height, diameter, (offsetx, offsety))
for mode in self.measureModes.values(): for mode in self.measureModes.values():
mode.boxGenerator.particleContainer = dset.particleContainer mode.method.particleContainer = dset.particleContainer
mode.boxGenerator.offset = (offsetx, offsety) mode.method.offset = (offsetx, offsety)
self.filterView.update_from_dataset(dset) self.filterView.update_from_dataset(dset)
self.activeMode.update_measure_viewItems() self.activeMode.update_measure_viewItems()
self.infoWidget.samplename = dset.name
self.infoWidget.update_label()
def _update_fiter_rotation(self): def _update_filter_rotation(self):
self.filterView.update_rotation(self.rotationSpinBox.value()) self.filterView.update_rotation(self.rotationSpinBox.value())
self.activeMode.send_measuredParticles_to_filterview() self.activeMode.send_measuredParticles_to_filterview()
class SampleInfoWidget(QtWidgets.QLabel):
def __init__(self):
super(SampleInfoWidget, self).__init__()
self.samplename: str = ''
self.result: SubsamplingResult = None
self.update_label()
@QtCore.pyqtSlot(SubsamplingResult)
def update_results(self, result: SubsamplingResult):
self.result = result
self.update_label()
def update_label(self) -> None:
if self.samplename == '':
self.setText('No sample loaded')
else:
mpFrac: float = round(self.result.origMPCount / self.result.origParticleCount * 100, 1)
self.setText(f'Sample: {self.samplename}, {self.result.origParticleCount} particles, '
f'MP Fraction = {mpFrac} %, '
f'MP Count Error = {round(self.result.mpCountError, 1)} % '
f'| MP Particle Count: Orig: {self.result.origMPCount}, '
f'Estimated: {round(self.result.estimMPCount)}')
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
app = QtWidgets.QApplication(sys.argv) app = QtWidgets.QApplication(sys.argv)
subsampling = MainView() subsampling = MainView()
subsampling.show() subsampling.show()
ret = app.exec_() ret = app.exec_()
\ No newline at end of file
from PyQt5 import QtCore, QtWidgets from PyQt5 import QtCore, QtWidgets
from gui.filterView import FilterView, MeasureBoxGraphItem from gui.filterView import FilterView, MeasureBoxGraphItem
from geometricMethods import BoxSelectionSubsamplingMethod, CrossBoxSubSampling, SpiralBoxSubsampling from methods import *
from geometricMethods import *
from evaluation import SubsamplingResult
class MeasureMode(QtCore.QObject): class MeasureMode(QtCore.QObject):
def __init__(self, relatedFilterView: FilterView): updatedResult: QtCore.pyqtSignal = QtCore.pyqtSignal(SubsamplingResult)
def __init__(self, relatedFilterView: FilterView) -> None:
super(MeasureMode, self).__init__() super(MeasureMode, self).__init__()
self.filterView: FilterView = relatedFilterView self.filterView: FilterView = relatedFilterView
self.uiControls: QtWidgets.QGroupBox = QtWidgets.QGroupBox() self.uiControls: QtWidgets.QGroupBox = QtWidgets.QGroupBox()
self.boxGenerator: BoxSelectionSubsamplingMethod = None self.method: SubsamplingMethod = None
self.subsamplingResult: SubsamplingResult = SubsamplingResult(self.method)
self.subParticles: list = [] self.subParticles: list = []
def get_control_groupBox(self) -> QtWidgets.QGroupBox: def get_control_groupBox(self) -> QtWidgets.QGroupBox:
return self.uiControls return self.uiControls
def update_measure_viewItems(self) -> None: def update_measure_viewItems(self) -> None:
raise NotImplementedError self.method.filterDiameter = self.filterView.filter.diameter
self.method.numBoxes = self.uiControls.numBoxesSpinbox.value()
self.method.fraction = self.uiControls.coverageSpinbox.value() / 100
topLefts: list = self.method.get_topLeft_of_boxes()
boxSize = self.method.boxSize
self.filterView.update_measure_boxes(topLefts, boxSize)
self.send_measuredParticles_to_filterview()
def send_measuredParticles_to_filterview(self) -> None: def send_measuredParticles_to_filterview(self) -> None:
if self.boxGenerator.particleContainer is not None: if self.method.particleContainer is not None:
subParticles = self.boxGenerator.apply_subsampling_method() subParticles = self.method.apply_subsampling_method()
self.subsamplingResult.method = self.method
self.subsamplingResult.reset_results()
self.subsamplingResult.add_result(self.method.particleContainer.particles, subParticles)
self.updatedResult.emit(self.subsamplingResult)
self.filterView.update_measured_particles(subParticles) self.filterView.update_measured_particles(subParticles)
class RandomMeasureMode(MeasureMode):
updatedResult: QtCore.pyqtSignal = QtCore.pyqtSignal(SubsamplingResult)
def __init__(self, filterView: FilterView):
super(RandomMeasureMode, self).__init__(filterView)
self.method: RandomSampling = RandomSampling(None)
self.uiControls = ParticleModeControlGroup(self, 'Random Particle Measurement')
def update_measure_viewItems(self) -> None:
self.method.fraction = self.uiControls.coverageSpinbox.value() / 100
self.filterView.update_measure_boxes([], 0.0)
self.send_measuredParticles_to_filterview()
class ParticleModeControlGroup(QtWidgets.QGroupBox):
def __init__(self, measureModeParent: MeasureMode, title: str) -> None:
super(ParticleModeControlGroup, self).__init__()
self.measureModeParent = measureModeParent
self.setTitle(title)
layout = QtWidgets.QHBoxLayout()
self.setLayout(layout)
layout.addWidget(QtWidgets.QLabel('Desired Coverage (%)'))
self.coverageSpinbox = QtWidgets.QSpinBox()
self.coverageSpinbox.setFixedWidth(50)
self.coverageSpinbox.setMinimum(0)
self.coverageSpinbox.setMaximum(100)
self.coverageSpinbox.setValue(10)
self.coverageSpinbox.valueChanged.connect(self._config_changed)
layout.addWidget(self.coverageSpinbox)
def _config_changed(self) -> None:
self.measureModeParent.update_measure_viewItems()
class CrossBoxMode(MeasureMode): class CrossBoxMode(MeasureMode):
def __init__(self, *args): def __init__(self, *args):
super(CrossBoxMode, self).__init__(*args) super(CrossBoxMode, self).__init__(*args)
self.uiControls = CrossBoxesControls(self) self.uiControls = CrossBoxesControls(self)
self.boxGenerator: CrossBoxSubSampling = CrossBoxSubSampling(None) self.method: CrossBoxSubSampling = CrossBoxSubSampling(None)
self.update_measure_viewItems() self.update_measure_viewItems()
def update_measure_viewItems(self) -> None: def update_measure_viewItems(self) -> None:
self.boxGenerator.filterDiameter = self.filterView.filter.diameter self.method.filterDiameter = self.filterView.filter.diameter
self.boxGenerator.numBoxesAcross = int(self.uiControls.numBoxesSelector.currentText()) self.method.numBoxesAcross = int(self.uiControls.numBoxesSelector.currentText())
desiredCoverage: int = self.uiControls.coverageSpinbox.value() desiredCoverage: int = self.uiControls.coverageSpinbox.value()
maxCoverage: int = int(self.boxGenerator.get_maximum_achievable_fraction() * 100) maxCoverage: int = int(self.method.get_maximum_achievable_fraction() * 100)
self.uiControls.set_to_max_possible_coverage(maxCoverage) self.uiControls.set_to_max_possible_coverage(maxCoverage)
if desiredCoverage > maxCoverage: if desiredCoverage > maxCoverage:
desiredCoverage = maxCoverage desiredCoverage = maxCoverage
self.boxGenerator.fraction = desiredCoverage / 100 self.method.fraction = desiredCoverage / 100
topLefts: list = self.boxGenerator.get_topLeft_of_boxes() topLefts: list = self.method.get_topLeft_of_boxes()
boxSize = self.boxGenerator.boxSize boxSize = self.method.boxSize
self.filterView.update_measure_boxes(topLefts, boxSize) self.filterView.update_measure_boxes(topLefts, boxSize)
self.send_measuredParticles_to_filterview() self.send_measuredParticles_to_filterview()
...@@ -88,33 +141,14 @@ class CrossBoxesControls(QtWidgets.QGroupBox): ...@@ -88,33 +141,14 @@ class CrossBoxesControls(QtWidgets.QGroupBox):
self.coverageSpinbox.valueChanged.connect(self._config_changed) self.coverageSpinbox.valueChanged.connect(self._config_changed)
class SpiralBoxMode(MeasureMode): class BoxControlGroup(QtWidgets.QGroupBox):
def __init__(self, *args):
super(SpiralBoxMode, self).__init__(*args)
self.uiControls: SpiralBoxControls = SpiralBoxControls(self)
self.boxGenerator: SpiralBoxSubsampling = SpiralBoxSubsampling(None)
self.update_measure_viewItems()
def update_measure_viewItems(self) -> None:
self.boxGenerator.filterDiameter = self.filterView.filter.diameter
self.boxGenerator.numBoxes = self.uiControls.numBoxesSpinbox.value()
self.boxGenerator.fraction = self.uiControls.coverageSpinbox.value() / 100
topLefts: list = self.boxGenerator.get_topLeft_of_boxes()
boxSize = self.boxGenerator.boxSize
self.filterView.update_measure_boxes(topLefts, boxSize)
self.send_measuredParticles_to_filterview()
class SpiralBoxControls(QtWidgets.QGroupBox):
""" """
Gives a groupbox with the controls for setting up the cross boxes. Gives a groupbox with the controls for setting up the cross boxes.
""" """
def __init__(self, measureModeParent: MeasureMode): def __init__(self, measureModeParent: MeasureMode, title: str) -> None:
super(SpiralBoxControls, self).__init__() super(BoxControlGroup, self).__init__()
self.setTitle('Spiral Box Controls') self.setTitle(title)
self.measureModeParent = measureModeParent self.measureModeParent = measureModeParent
layout = QtWidgets.QHBoxLayout() layout = QtWidgets.QHBoxLayout()
self.setLayout(layout) self.setLayout(layout)
...@@ -136,6 +170,46 @@ class SpiralBoxControls(QtWidgets.QGroupBox): ...@@ -136,6 +170,46 @@ class SpiralBoxControls(QtWidgets.QGroupBox):
self.coverageSpinbox.valueChanged.connect(self._config_changed) self.coverageSpinbox.valueChanged.connect(self._config_changed)
layout.addWidget(self.coverageSpinbox) layout.addWidget(self.coverageSpinbox)
def _config_changed(self): def _config_changed(self) -> None:
if self.numBoxesSpinbox.value() > 0: if self.numBoxesSpinbox.value() > 0:
numBoxes: int = self.numBoxesSpinbox.value()
self.measureModeParent.method.numBoxes = numBoxes
maxCoverage: float = self.measureModeParent.method.get_maximum_achievable_fraction()
self.set_to_max_possible_coverage(round(maxCoverage * 100))
self.measureModeParent.update_measure_viewItems() self.measureModeParent.update_measure_viewItems()
def set_to_max_possible_coverage(self, maxCoverage: int) -> None:
"""
Adjusts maximum of coverage spinbox and, if necessary, caps the current value.
:param maxCoverage: the maximum pssible converage IN PERCENT!!
:return:
"""
self.coverageSpinbox.setMaximum(maxCoverage)
if maxCoverage < self.coverageSpinbox.value():
self.coverageSpinbox.valueChanged.disconnect()
self.coverageSpinbox.setValue(maxCoverage)
self.coverageSpinbox.valueChanged.connect(self._config_changed)
class SpiralBoxMode(MeasureMode):
def __init__(self, *args):
super(SpiralBoxMode, self).__init__(*args)
self.uiControls: BoxControlGroup = BoxControlGroup(self, 'Spiral Box Controls')
self.method: SpiralBoxSubsampling = SpiralBoxSubsampling(None)
self.update_measure_viewItems()
class RandomBoxMode(MeasureMode):
def __init__(self, *args):
super(RandomBoxMode, self).__init__(*args)
self.uiControls: BoxControlGroup = BoxControlGroup(self, 'Random Box Controls')
self.method: RandomBoxSampling = RandomBoxSampling(None)
self.update_measure_viewItems()
class QuarterRandomBoxMode(MeasureMode):
def __init__(self, *args):
super(QuarterRandomBoxMode, self).__init__(*args)
self.uiControls: BoxControlGroup = BoxControlGroup(self, 'Quarter Random Box Controls')
self.method: RandomQuarterBoxes = RandomQuarterBoxes(None)
self.update_measure_viewItems()
...@@ -23,7 +23,6 @@ def timingDecorator(callingFunction): ...@@ -23,7 +23,6 @@ def timingDecorator(callingFunction):
class ParticleBinSorter(object): class ParticleBinSorter(object):
def __init__(self): def __init__(self):
super(ParticleBinSorter, self).__init__() super(ParticleBinSorter, self).__init__()
self.bins = [5, 10, 20, 50, 100, 200, 500] self.bins = [5, 10, 20, 50, 100, 200, 500]
...@@ -153,6 +152,16 @@ def get_filterDimensions_from_dataset(dataset: dataset.DataSet) -> tuple: ...@@ -153,6 +152,16 @@ def get_filterDimensions_from_dataset(dataset: dataset.DataSet) -> tuple:
return offset, diameter, [width, height] return offset, diameter, [width, height]
def get_center_from_filter_dimensions(offsetXY: tuple, diameter: float) -> np.ndarray:
"""
Calculates the center coordinates of a filter.
:return:
"""
center: np.ndarray = np.array([round(offsetXY[0] + diameter/2),
round(offsetXY[1] + diameter/2)], dtype=np.int32)
return center
def convert_length_to_pixels(dataset: dataset.DataSet, length: float) -> float: def convert_length_to_pixels(dataset: dataset.DataSet, length: float) -> float:
""" """
:param dataset: dataset to use for conversion :param dataset: dataset to use for conversion
......
import os import os
import pickle import pickle
from evaluation import TotalResults from evaluation import TotalResults
from helpers import timingDecorator
def load_results(fname: str) -> TotalResults: def load_results(fname: str) -> TotalResults:
# TODO: REMVOE DATASET FROM SAMPLERESULTS, OTHERWISE THE FILESIZE IS GOING TO BE HUGE
res: TotalResults = None res: TotalResults = None
if os.path.exists(fname): if os.path.exists(fname):
with open(fname, "rb") as fp: with open(fname, "rb") as fp:
res = pickle.load(fp) res = pickle.load(fp)
return res return res
return None
def save_results(fname: str, result: TotalResults) -> None: def save_results(fname: str, result: TotalResults) -> None:
storedDsets: dict = {}
for sampleRes in result.sampleResults:
storedDsets[sampleRes.sampleName] = sampleRes.dataset
sampleRes.dataset = None
with open(fname, "wb") as fp: with open(fname, "wb") as fp:
pickle.dump(result, fp, protocol=-1) pickle.dump(result, fp, protocol=-1)
for sampleRes in result.sampleResults:
sampleRes.dataset = storedDsets[sampleRes.sampleName]
def get_pkls_from_directory(dirPath: str) -> dict: def get_pkls_from_directory(dirPath: str) -> dict:
""" """
......
...@@ -11,6 +11,8 @@ from helpers import ParticleBinSorter ...@@ -11,6 +11,8 @@ from helpers import ParticleBinSorter
class SubsamplingMethod(object): class SubsamplingMethod(object):
randomSeed = 15203018
def __init__(self, particleConatainer, desiredFraction: float = 0.2): def __init__(self, particleConatainer, desiredFraction: float = 0.2):
super(SubsamplingMethod, self).__init__() super(SubsamplingMethod, self).__init__()
self.particleContainer = particleConatainer self.particleContainer = particleConatainer
...@@ -65,6 +67,14 @@ class SubsamplingMethod(object): ...@@ -65,6 +67,14 @@ class SubsamplingMethod(object):
matches = (self.label.lower().find(pattern.lower()) != -1) matches = (self.label.lower().find(pattern.lower()) != -1)
return matches return matches
def config_is_valid(self) -> bool:
isValid: bool = False
if self.fraction <= self.get_maximum_achievable_fraction():
isValid = True
return isValid
def get_maximum_achievable_fraction(self) -> float:
raise NotImplementedError
class RandomSampling(SubsamplingMethod): class RandomSampling(SubsamplingMethod):
@property @property
...@@ -82,6 +92,9 @@ class RandomSampling(SubsamplingMethod): ...@@ -82,6 +92,9 @@ class RandomSampling(SubsamplingMethod):
def equals(self, otherMethod) -> bool: def equals(self, otherMethod) -> bool:
return type(otherMethod) == type(self) and otherMethod.fraction == self.fraction return type(otherMethod) == type(self) and otherMethod.fraction == self.fraction
def get_maximum_achievable_fraction(self) -> float:
return 1.0
class SizeBinFractioning(SubsamplingMethod): class SizeBinFractioning(SubsamplingMethod):
...@@ -117,3 +130,6 @@ class SizeBinFractioning(SubsamplingMethod): ...@@ -117,3 +130,6 @@ class SizeBinFractioning(SubsamplingMethod):
def equals(self, otherMethod) -> bool: def equals(self, otherMethod) -> bool:
return type(otherMethod) == type(self) and otherMethod.fraction == self.fraction return type(otherMethod) == type(self) and otherMethod.fraction == self.fraction
def get_maximum_achievable_fraction(self) -> float:
return 1.0
\ No newline at end of file
import matplotlib.pyplot as plt # import matplotlib.pyplot as plt
from matplotlib.figure import Figure
import time import time
from evaluation import TotalResults, SampleResult from evaluation import TotalResults, SampleResult
from input_output import get_pkls_from_directory, get_attributes_from_foldername, save_results, load_results from input_output import get_pkls_from_directory, get_attributes_from_foldername, save_results, load_results
from graphs import get_error_vs_frac_plot
""" """
IMPORTANT!!! IMPORTANT!!!
SET GEPARD TO EVALUATION BRANCH (WITHOUT THE TILING STUFF), OTHERWISE SOME OF THE LEGACY CONVERTS MIGHT FAIL.. SET GEPARD TO EVALUATION BRANCH (WITHOUT THE TILING STUFF), OTHERWISE SOME OF THE LEGACY CONVERTS MIGHT FAIL..
""" """
if __name__ == '__main__':
results: TotalResults = TotalResults() # results: TotalResults = TotalResults()
pklsInFolders = get_pkls_from_directory(r'C:\Users\xbrjos\Desktop\temp MP\NewDatasets') # pklsInFolders = get_pkls_from_directory(r'C:\Users\xbrjos\Desktop\temp MP\NewDatasets')
#
for folder in pklsInFolders.keys(): # for folder in pklsInFolders.keys():
for samplePath in pklsInFolders[folder]: # for samplePath in pklsInFolders[folder]:
newSampleResult: SampleResult = results.add_sample(samplePath) # newSampleResult: SampleResult = results.add_sample(samplePath)
for attr in get_attributes_from_foldername(folder): # for attr in get_attributes_from_foldername(folder):
newSampleResult.set_attribute(attr) # newSampleResult.set_attribute(attr)
#
t0 = time.time() # t0 = time.time()
results.update_all() # results.update_all()
print('updating all took', time.time()-t0, 'seconds') # print('updating all took', time.time()-t0, 'seconds')
#
save_results('results1.res', results) # save_results('results2_without_rot.res', results)
# results: TotalResults = load_results('results1.res') results: TotalResults = load_results('results2.res')
# results.update_all(force=True)
# save_results('results1.res', results) plot: Figure = get_error_vs_frac_plot(results, attributes=[[]],
methods=[['random subs', 'sizebin', '5 boxes', '15']], standarddevs=False)
plt.clf() # plot: Figure = get_error_vs_frac_plot(results, attributes=[['air', 'water'], ['sediment', 'soil', 'beach', 'slush']],
errorPerFraction: dict = results.get_error_vs_fraction_data(attributes=['air', 'water'], # methods=[['random layout (7', 'random layout (1']]*2)
methods=['chemo', 'sizeBin', 'random']) # methods=[[]]*2)
# methods=[['Random Subsampling', 'Sizebin']] * 2)
plt.subplot(121) # methods=[['layout (7', 'layout (10', 'layout (15', 'cross', 'random subsampling', 'sizebin']] * 2)
for methodLabel in errorPerFraction.keys(): plot.show()
fractions: list = list(errorPerFraction[methodLabel].keys())
errors: list = list(errorPerFraction[methodLabel].values())
plt.plot(fractions, errors)
plt.scatter(fractions, errors, label=methodLabel)
plt.title('Air/Water sample', fontSize=15)
plt.xscale('log')
plt.xlabel('measured fraction', fontsize=12)
plt.ylabel('mpCountError (%)', fontsize=12)
plt.ylim([0, 100])
plt.legend()
errorPerFraction: dict = results.get_error_vs_fraction_data(attributes=['sediment', 'soil', 'beach', 'slush'],
methods=['chemo', 'sizeBin', 'random'])
plt.subplot(122)
for methodLabel in errorPerFraction.keys():
fractions: list = list(errorPerFraction[methodLabel].keys())
errors: list = list(errorPerFraction[methodLabel].values())
plt.plot(fractions, errors)
plt.scatter(fractions, errors, label=methodLabel)
plt.title('Sediment/Beach/Slush sample', fontSize=15)
plt.xscale('log')
plt.xlabel('measured fraction', fontsize=12)
plt.ylabel('mpCountError (%)', fontsize=12)
plt.ylim([0, 100])
plt.legend()
plt.show()
...@@ -2,9 +2,23 @@ import numpy as np ...@@ -2,9 +2,23 @@ import numpy as np
import sys import sys
sys.path.append("C://Users//xbrjos//Desktop//Python") sys.path.append("C://Users//xbrjos//Desktop//Python")
import gepard import gepard
from gepard.dataset import DataSet
from gepard.analysis.particleContainer import ParticleContainer from gepard.analysis.particleContainer import ParticleContainer
def setMaxDim(dataset: DataSet, imgSize: float, minX: float, maxX: float, minY: float, maxY: float) -> None:
dataset.maxdim = minX + imgSize/2, maxY - imgSize/2, maxX - imgSize/2, minY + imgSize/2
def get_default_DataSet() -> DataSet:
dset: DataSet = DataSet('tests/default.pkl')
dset.imagescanMode = 'df'
dset.imagedim_df = [10, 10]
dset.pixelscale_df = 1.0
setMaxDim(dset, 10, 0, 10, 0, 10)
return dset
def get_default_ParticleContainer() -> ParticleContainer: def get_default_ParticleContainer() -> ParticleContainer:
particleContainer: ParticleContainer = ParticleContainer(None) particleContainer: ParticleContainer = ParticleContainer(None)
particleContainer.initializeParticles(4) particleContainer.initializeParticles(4)
...@@ -13,4 +27,10 @@ def get_default_ParticleContainer() -> ParticleContainer: ...@@ -13,4 +27,10 @@ def get_default_ParticleContainer() -> ParticleContainer:
x = 10*i x = 10*i
contours.append(np.array([[[x, 0]], [[x+10, 0]], [[x+10, 10]], [[x, 10]]], dtype=np.int32)) contours.append(np.array([[[x, 0]], [[x+10, 0]], [[x+10, 10]], [[x, 10]]], dtype=np.int32))
particleContainer.setParticleContours(contours) particleContainer.setParticleContours(contours)
particleContainer.particles[0].color = 'red'
particleContainer.particles[1].color = 'blue'
particleContainer.particles[2].color = 'green'
particleContainer.particles[3].color = 'transparent'
return particleContainer return particleContainer
This diff is collapsed.
...@@ -2,14 +2,18 @@ import unittest ...@@ -2,14 +2,18 @@ import unittest
import numpy as np import numpy as np
import sys import sys
sys.path.append("C://Users//xbrjos//Desktop//Python") sys.path.append("C://Users//xbrjos//Desktop//Python")
from gepard import dataset
from gepard.analysis.particleContainer import ParticleContainer from gepard.analysis.particleContainer import ParticleContainer
from datasetOperations import ParticleVariations from datasetOperations import ParticleVariations
from helpers_for_test import get_default_ParticleContainer from helpers_for_test import get_default_ParticleContainer, get_default_DataSet
class TestParticleVariations(unittest.TestCase): class TestParticleVariations(unittest.TestCase):
def test_get_particleContainer_variations(self): def test_get_particleContainer_variations(self):
dset: dataset.DataSet = get_default_DataSet()
particleContainer: ParticleContainer = get_default_ParticleContainer() particleContainer: ParticleContainer = get_default_ParticleContainer()
dset.particleContainer = particleContainer
contours = particleContainer.getParticleContours() contours = particleContainer.getParticleContours()
center: tuple = round(np.mean(contours[:][0][0])), \ center: tuple = round(np.mean(contours[:][0][0])), \
...@@ -17,7 +21,7 @@ class TestParticleVariations(unittest.TestCase): ...@@ -17,7 +21,7 @@ class TestParticleVariations(unittest.TestCase):
center: np.ndarray = np.array(center, dtype=np.int32) center: np.ndarray = np.array(center, dtype=np.int32)
for numVariations in [0, 1, 10, 20]: for numVariations in [0, 1, 10, 20]:
particleVariations: ParticleVariations = ParticleVariations(particleContainer, numVariations) particleVariations: ParticleVariations = ParticleVariations(dset, numVariations)
foundContours: list = [] foundContours: list = []
if numVariations == 0: if numVariations == 0:
...@@ -39,7 +43,7 @@ class TestParticleVariations(unittest.TestCase): ...@@ -39,7 +43,7 @@ class TestParticleVariations(unittest.TestCase):
self.assertEqual(index, numVariations-1) self.assertEqual(index, numVariations-1)
def test_get_angles(self): def test_get_angles(self):
particleVariations: ParticleVariations = ParticleVariations(None, 2) particleVariations: ParticleVariations = ParticleVariations(dataset.DataSet('fakepath/fake.pkl'), 2)
angles: list = list(particleVariations._get_angles()) angles: list = list(particleVariations._get_angles())
self.assertEqual(angles, [0, 180]) self.assertEqual(angles, [0, 180])
......
This diff is collapsed.
This diff is collapsed.
...@@ -15,6 +15,7 @@ from PyQt5 import QtCore, QtGui ...@@ -15,6 +15,7 @@ from PyQt5 import QtCore, QtGui
import gepard import gepard
from gepard.analysis.particleAndMeasurement import Particle from gepard.analysis.particleAndMeasurement import Particle
from gepard import dataset from gepard import dataset
from helpers_for_test import get_default_DataSet, setMaxDim
class TestBinSorter(unittest.TestCase): class TestBinSorter(unittest.TestCase):
...@@ -166,32 +167,27 @@ class TestOther(unittest.TestCase): ...@@ -166,32 +167,27 @@ class TestOther(unittest.TestCase):
class TestDatasetOperations(unittest.TestCase): class TestDatasetOperations(unittest.TestCase):
def setUp(self) -> None: def setUp(self) -> None:
self.dataset: dataset.DataSet = dataset.DataSet('test') self.dataset = get_default_DataSet()
self.dataset.imagescanMode = 'df'
def test_get_filtersize(self): def test_get_filtersize(self):
def setMaxDim():
self.dataset.maxdim = minX + imgdim / 2, maxY - imgdim / 2, maxX - imgdim / 2, minY + imgdim / 2
imgdim = 10 imgdim = 10
self.dataset.imagedim_df = [imgdim, imgdim]
minX, maxX, minY, maxY = 0, 10, 0, 10 minX, maxX, minY, maxY = 0, 10, 0, 10
setMaxDim() setMaxDim(self.dataset, imgdim, minX, maxX, minY, maxY)
offset, diameter, widthHeight = helpers.get_filterDimensions_from_dataset(self.dataset) offset, diameter, widthHeight = helpers.get_filterDimensions_from_dataset(self.dataset)
self.assertEqual(diameter, 10) self.assertEqual(diameter, 10)
self.assertEqual(offset, (0, 0)) self.assertEqual(offset, (0, 0))
self.assertEqual(widthHeight, [10, 10]) self.assertEqual(widthHeight, [10, 10])
minX, maxX, minY, maxY = -10, 10, -10, 10 minX, maxX, minY, maxY = -10, 10, -10, 10
setMaxDim() setMaxDim(self.dataset, imgdim, minX, maxX, minY, maxY)
offset, diameter, widthHeight = helpers.get_filterDimensions_from_dataset(self.dataset) offset, diameter, widthHeight = helpers.get_filterDimensions_from_dataset(self.dataset)
self.assertEqual(diameter, 20) self.assertEqual(diameter, 20)
self.assertEqual(widthHeight, [20, 20]) self.assertEqual(widthHeight, [20, 20])
self.assertEqual(offset, (0, 0)) self.assertEqual(offset, (0, 0))
minX, maxX, minY, maxY = 0, 20, 0, 10 minX, maxX, minY, maxY = 0, 20, 0, 10
setMaxDim() setMaxDim(self.dataset, imgdim, minX, maxX, minY, maxY)
offset, diameter, widthHeight = helpers.get_filterDimensions_from_dataset(self.dataset) offset, diameter, widthHeight = helpers.get_filterDimensions_from_dataset(self.dataset)
self.assertEqual(diameter, 10) self.assertEqual(diameter, 10)
self.assertEqual(widthHeight, [20, 10]) self.assertEqual(widthHeight, [20, 10])
...@@ -209,3 +205,11 @@ class TestDatasetOperations(unittest.TestCase): ...@@ -209,3 +205,11 @@ class TestDatasetOperations(unittest.TestCase):
self.assertEqual(helpers.convert_length_to_pixels(self.dataset, diameter), 20) self.assertEqual(helpers.convert_length_to_pixels(self.dataset, diameter), 20)
self.assertEqual(helpers.convert_length_to_pixels(self.dataset, widthHeight[0]), 40) self.assertEqual(helpers.convert_length_to_pixels(self.dataset, widthHeight[0]), 40)
self.assertEqual(helpers.convert_length_to_pixels(self.dataset, widthHeight[1]), 20) self.assertEqual(helpers.convert_length_to_pixels(self.dataset, widthHeight[1]), 20)
def test_get_center_from_filter_dimensions(self):
for offset in [(0, 0), (5, 0), (0, 5), (-5, 10), (-7, -2.5)]:
for diameter in [5, 10, 20]:
center: np.ndarray = helpers.get_center_from_filter_dimensions(offset, diameter)
self.assertEqual(center[0], round(diameter/2 + offset[0]))
self.assertEqual(center[1], round(diameter/2 + offset[1]))
self.assertTrue(type(center[0]) == np.int32) # has to be np.int32 for use in rotate_contour cython