Commit aec15820 authored by Josef Brandt's avatar Josef Brandt

Merge branch 'Development'

parents b02245b5 68561321
......@@ -183,7 +183,7 @@ class ChemometricSubsampling(SubsamplingMethod):
if not abs(totalPointsAdded - numPointsToSelect) <= 1:
print('error')
# assert abs(totalPointsAdded - numPointsToSelect) <= 1
assert abs(totalPointsAdded - numPointsToSelect) <= 1
for clusterIndex in pointsPerCluster.keys():
assert 0 <= pointsPerCluster[clusterIndex] <= len(labels[labels == clusterIndex])
return pointsPerCluster
......
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:
sys.argv.append("build_ext")
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(
name="rotate contour around reference point",
ext_modules=cythonize([ext], annotate=True), # accepts a glob pattern
name="get a given number of random topLefts",
ext_modules=cythonize("randoms.pyx", annotate=True), # accepts a glob pattern
include_dirs=[np.get_include()]
)
\ No newline at end of file
)
......@@ -2,23 +2,28 @@ import copy
import numpy as np
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
from gepard import dataset
from gepard.analysis.particleContainer import ParticleContainer
from cythonModules import rotateContour
from helpers import get_filterDimensions_from_dataset, get_center_from_filter_dimensions, convert_length_to_pixels
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__()
self.origParticleContainer = particleContainer
self.dataset: dataset.DataSet = dataset
self.origParticleContainer: ParticleContainer = self.dataset.particleContainer
self.numVariations = numVariations
def get_particleContainer_variations(self) -> ParticleContainer:
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
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()
for i in range(self.numVariations):
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
from gepard import dataset
import helpers
from cythonModules import rotateContour as rc
from evaluation import is_MP_particle
class FilterView(QtWidgets.QGraphicsView):
......@@ -49,12 +49,11 @@ class FilterView(QtWidgets.QGraphicsView):
self._update_particle_contours()
self._fit_to_window()
@helpers.timingDecorator
def update_rotation(self, newRotation: int) -> None:
if newRotation != self.rotation:
angle: float = np.float(newRotation-self.rotation)
center: np.ndarray = np.array([self.filter.circleOffset[0] + self.filter.diameter/2,
self.filter.circleOffset[1] + self.filter.diameter/2], dtype=np.int32)
center: np.ndarray = helpers.get_center_from_filter_dimensions(self.filter.circleOffset,
self.filter.diameter)
for particle in self.dataset.particleContainer.particles:
particle.contour = rc.rotate_contour_around_point(particle.contour, center, angle)
......@@ -62,12 +61,11 @@ class FilterView(QtWidgets.QGraphicsView):
self._update_particle_contours()
self.rotation = newRotation
@helpers.timingDecorator
def _update_particle_contours(self) -> None:
self._remove_particle_contours()
if self.dataset is not None:
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.contourItems.append(newContour)
......@@ -169,12 +167,13 @@ class MeasureBoxGraphItem(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__()
self.setZValue(1)
self.setPos(pos[0], pos[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.contourData = contourData
self.polygon = None
......@@ -201,11 +200,13 @@ class ParticleContour(QtWidgets.QGraphicsItem):
def paint(self, painter, option, widget) -> None:
if self.polygon is not None:
if self.isMeasured:
if self.isMP:
painter.setPen(QtCore.Qt.darkRed)
painter.setBrush(QtCore.Qt.red)
else:
painter.setPen(QtCore.Qt.darkCyan)
painter.setBrush(QtCore.Qt.cyan)
painter.setPen(QtCore.Qt.darkBlue)
painter.setBrush(QtCore.Qt.blue)
painter.setOpacity(1 if self.isMeasured else 0.2)
painter.drawPolygon(self.polygon)
from PyQt5 import QtWidgets
from PyQt5 import QtWidgets, QtCore
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
import gepard
from gepard import dataset
from gui.filterView import FilterView
from gui.measureModes import MeasureMode, CrossBoxMode, CrossBoxesControls, SpiralBoxMode
from gui.measureModes import *
import helpers
from evaluation import SubsamplingResult
class MainView(QtWidgets.QWidget):
......@@ -30,7 +31,7 @@ class MainView(QtWidgets.QWidget):
self.rotationSpinBox.setMaximum(359)
self.rotationSpinBox.setValue(0)
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.controlGroupLayout = QtWidgets.QHBoxLayout()
......@@ -44,17 +45,29 @@ class MainView(QtWidgets.QWidget):
self.controlGroupLayout.addWidget(self.activeModeControl)
self.controlGroupLayout.addStretch()
self.infoWidget: SampleInfoWidget = SampleInfoWidget()
self.layout.addWidget(self.controlGroup)
self.layout.addWidget(self.infoWidget)
self.filterView = FilterView()
self.layout.addWidget(self.filterView)
self._add_measure_modes()
self._switch_to_default_mode()
def _add_measure_modes(self) -> None:
self.measureModes['spiralSelection'] = SpiralBoxMode(self.filterView)
self.measureModes['crossSelection'] = CrossBoxMode(self.filterView)
self.modeSelector.addItem('spiralSelection')
self.modeSelector.addItem('crossSelection')
self.measureModes['Random Particle Selection'] = RandomMeasureMode(self.filterView)
self.measureModes['Spiral Box Selection'] = SpiralBoxMode(self.filterView)
self.measureModes['Cross Box Selection'] = CrossBoxMode(self.filterView)
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:
modes: list = list(self.measureModes.keys())
......@@ -76,7 +89,6 @@ class MainView(QtWidgets.QWidget):
self.activeMode.update_measure_viewItems()
@helpers.timingDecorator
def _load_dataset(self) -> None:
fname = QtWidgets.QFileDialog.getOpenFileName(self, 'Select .pkl file', filter='pkl file (*.pkl)')
if fname[0] != '':
......@@ -96,20 +108,46 @@ class MainView(QtWidgets.QWidget):
self.filterView.filter.update_filterSize(width, height, diameter, (offsetx, offsety))
for mode in self.measureModes.values():
mode.boxGenerator.particleContainer = dset.particleContainer
mode.boxGenerator.offset = (offsetx, offsety)
mode.method.particleContainer = dset.particleContainer
mode.method.offset = (offsetx, offsety)
self.filterView.update_from_dataset(dset)
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.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__':
import sys
app = QtWidgets.QApplication(sys.argv)
subsampling = MainView()
subsampling.show()
ret = app.exec_()
\ No newline at end of file
ret = app.exec_()
from PyQt5 import QtCore, QtWidgets
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):
def __init__(self, relatedFilterView: FilterView):
updatedResult: QtCore.pyqtSignal = QtCore.pyqtSignal(SubsamplingResult)
def __init__(self, relatedFilterView: FilterView) -> None:
super(MeasureMode, self).__init__()
self.filterView: FilterView = relatedFilterView
self.uiControls: QtWidgets.QGroupBox = QtWidgets.QGroupBox()
self.boxGenerator: BoxSelectionSubsamplingMethod = None
self.method: SubsamplingMethod = None
self.subsamplingResult: SubsamplingResult = SubsamplingResult(self.method)
self.subParticles: list = []
def get_control_groupBox(self) -> QtWidgets.QGroupBox:
return self.uiControls
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:
if self.boxGenerator.particleContainer is not None:
subParticles = self.boxGenerator.apply_subsampling_method()
if self.method.particleContainer is not None:
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)
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):
def __init__(self, *args):
super(CrossBoxMode, self).__init__(*args)
self.uiControls = CrossBoxesControls(self)
self.boxGenerator: CrossBoxSubSampling = CrossBoxSubSampling(None)
self.method: CrossBoxSubSampling = CrossBoxSubSampling(None)
self.update_measure_viewItems()
def update_measure_viewItems(self) -> None:
self.boxGenerator.filterDiameter = self.filterView.filter.diameter
self.boxGenerator.numBoxesAcross = int(self.uiControls.numBoxesSelector.currentText())
self.method.filterDiameter = self.filterView.filter.diameter
self.method.numBoxesAcross = int(self.uiControls.numBoxesSelector.currentText())
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)
if desiredCoverage > maxCoverage:
desiredCoverage = maxCoverage
self.boxGenerator.fraction = desiredCoverage / 100
self.method.fraction = desiredCoverage / 100
topLefts: list = self.boxGenerator.get_topLeft_of_boxes()
boxSize = self.boxGenerator.boxSize
topLefts: list = self.method.get_topLeft_of_boxes()
boxSize = self.method.boxSize
self.filterView.update_measure_boxes(topLefts, boxSize)
self.send_measuredParticles_to_filterview()
......@@ -88,33 +141,14 @@ class CrossBoxesControls(QtWidgets.QGroupBox):
self.coverageSpinbox.valueChanged.connect(self._config_changed)
class SpiralBoxMode(MeasureMode):
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):
class BoxControlGroup(QtWidgets.QGroupBox):
"""
Gives a groupbox with the controls for setting up the cross boxes.
"""
def __init__(self, measureModeParent: MeasureMode):
super(SpiralBoxControls, self).__init__()
self.setTitle('Spiral Box Controls')
def __init__(self, measureModeParent: MeasureMode, title: str) -> None:
super(BoxControlGroup, self).__init__()
self.setTitle(title)
self.measureModeParent = measureModeParent
layout = QtWidgets.QHBoxLayout()
self.setLayout(layout)
......@@ -136,6 +170,46 @@ class SpiralBoxControls(QtWidgets.QGroupBox):
self.coverageSpinbox.valueChanged.connect(self._config_changed)
layout.addWidget(self.coverageSpinbox)
def _config_changed(self):
def _config_changed(self) -> None:
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()
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):
class ParticleBinSorter(object):
def __init__(self):
super(ParticleBinSorter, self).__init__()
self.bins = [5, 10, 20, 50, 100, 200, 500]
......@@ -153,6 +152,16 @@ def get_filterDimensions_from_dataset(dataset: dataset.DataSet) -> tuple:
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:
"""
:param dataset: dataset to use for conversion
......
import os
import pickle
from evaluation import TotalResults
from helpers import timingDecorator
def load_results(fname: str) -> TotalResults:
# TODO: REMVOE DATASET FROM SAMPLERESULTS, OTHERWISE THE FILESIZE IS GOING TO BE HUGE
res: TotalResults = None
if os.path.exists(fname):
with open(fname, "rb") as fp:
res = pickle.load(fp)
return res
return 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:
pickle.dump(result, fp, protocol=-1)
for sampleRes in result.sampleResults:
sampleRes.dataset = storedDsets[sampleRes.sampleName]
def get_pkls_from_directory(dirPath: str) -> dict:
"""
......
......@@ -11,6 +11,8 @@ from helpers import ParticleBinSorter
class SubsamplingMethod(object):
randomSeed = 15203018
def __init__(self, particleConatainer, desiredFraction: float = 0.2):
super(SubsamplingMethod, self).__init__()
self.particleContainer = particleConatainer
......@@ -65,6 +67,14 @@ class SubsamplingMethod(object):
matches = (self.label.lower().find(pattern.lower()) != -1)
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):
@property
......@@ -82,6 +92,9 @@ class RandomSampling(SubsamplingMethod):
def equals(self, otherMethod) -> bool:
return type(otherMethod) == type(self) and otherMethod.fraction == self.fraction
def get_maximum_achievable_fraction(self) -> float:
return 1.0
class SizeBinFractioning(SubsamplingMethod):
......@@ -117,3 +130,6 @@ class SizeBinFractioning(SubsamplingMethod):
def equals(self, otherMethod) -> bool:
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.pyplo