Commit 2fa6a43f authored by Josef Brandt's avatar Josef Brandt

First Commit, CrossBoxSelection working in gui

parent 2c8504fb
.idea/
__pycache__/
*.png
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 22 13:57:28 2020
@author: luna
"""
from helpers import ParticleBinSorter
class ResultComparer(object):
def _get_mp_count_error_per_bin(self, allParticles, subParticles, fractionMeasured):
binSorter = ParticleBinSorter()
allParticlesInBins = binSorter.sort_particles_into_bins(allParticles)
subParticlesInBins = binSorter.sort_particles_into_bins(subParticles)
mpCountErrorsPerBin = []
for allParticleBin, subParticleBin in zip(allParticlesInBins, subParticlesInBins):
mpCountErrorsPerBin.append(self._get_mp_count_error(allParticleBin, subParticleBin, fractionMeasured))
return binSorter.bins, mpCountErrorsPerBin
def _get_mp_count_error(self, allParticles, subParticles, fractionMeasured):
numMPOrig = self._get_number_of_MP_particles(allParticles)
numMPEstimate = self._get_number_of_MP_particles(subParticles) / fractionMeasured
if numMPOrig != 0:
mpCountError = self._get_error_from_values(numMPOrig, numMPEstimate)
elif numMPEstimate == 0:
mpCountError = 0
else:
raise Exception #> 0 particles in subsample, whereas none in entire sample. This cannot be!
return mpCountError
def _get_error_from_values(self, exact, estimate):
assert(exact != 0)
return abs(exact - estimate) / exact
def _get_number_of_MP_particles(self, particleList):
mpPatterns = ['poly', 'rubber', 'pb', 'pr', 'pg', 'py', 'pv']
numMPParticles = 0
for particle in particleList:
assignment = particle.getParticleAssignment()
for pattern in mpPatterns:
if assignment.lower().find(pattern) != -1:
numMPParticles += 1
break
return numMPParticles
\ No newline at end of file
from methods import SubsamplingMethod
class CrossBoxSelector(SubsamplingMethod):
def __init__(self, particleContainer, desiredFraction:float = 0.1) -> None:
super(CrossBoxSelector, self).__init__(particleContainer, desiredFraction)
self.fraction = desiredFraction
self.filterWidth: float = 1000
self.filterHeight: float = 1000
self.numBoxesAcross: int = 3 #either 3 or 5
@property
def boxSize(self) -> float:
assert self.get_maximum_achievable_fraction() >= self.fraction
totalBoxArea: float = ((self.filterWidth*self.filterHeight)*self.fraction)
boxArea: float = totalBoxArea / (2*self.numBoxesAcross - 1)
return boxArea**0.5
def get_topLeft_of_boxes(self) -> list:
topLeftCorners: list = []
boxSize = self.boxSize
xStartCoordinates: list = self._get_horizontal_box_starts(boxSize)
yStartCoordinates: list = self._get_vertical_box_starts(boxSize)
middleXCoordinate: float = xStartCoordinates[self.numBoxesAcross//2]
middleYCoordinate: float = yStartCoordinates[self.numBoxesAcross//2]
for i in range(self.numBoxesAcross):
topLeftCorners.append((middleXCoordinate, yStartCoordinates[i]))
if i != self.numBoxesAcross//2:
topLeftCorners.append((xStartCoordinates[i], middleYCoordinate))
return topLeftCorners
def get_maximum_achievable_fraction(self) -> float:
"""
Returns the maximum achievable fraction, given the desired number of boxes across.
It is with respect to a rectangular filter of width*height, for circular filter this has to be divided by 0.786
:return float:
"""
maxBoxWidth: float = self.filterWidth / self.numBoxesAcross
maxBoxHeight: float = self.filterHeight / self.numBoxesAcross
numBoxes: int = 2*self.numBoxesAcross - 1
totalBoxArea: float = numBoxes * (maxBoxWidth * maxBoxHeight)
return totalBoxArea / (self.filterHeight * self.filterWidth)
def _get_horizontal_box_starts(self, boxSize: float) -> list:
"""
Returns a list of width-values at which the individual boxes start
:param boxSize:
:return list:
"""
return self._get_box_starts(self.filterWidth, boxSize)
def _get_vertical_box_starts(self, boxSize: float) -> list:
"""
Returns a list of height-values at which the individual boxes start
:param boxSize:
:return list:
"""
return self._get_box_starts(self.filterHeight, boxSize)
def _get_box_starts(self, filterSize: float, boxSize: float) -> list:
maxBoxSize: float = filterSize / self.numBoxesAcross
assert maxBoxSize >= boxSize
tileStarts: list = []
for i in range(self.numBoxesAcross):
start: float = i * filterSize / self.numBoxesAcross + (maxBoxSize - boxSize) / 2
tileStarts.append(start)
return tileStarts
\ No newline at end of file
from PyQt5 import QtGui, QtWidgets, QtCore
class FilterView(QtWidgets.QGraphicsView):
def __init__(self):
super(FilterView, self).__init__()
self.setWindowTitle('FilterView')
scene = QtWidgets.QGraphicsScene(self)
scene.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex)
scene.setBackgroundBrush(QtCore.Qt.darkGray)
self.setScene(scene)
self.setCacheMode(QtWidgets.QGraphicsView.CacheBackground)
self.setViewportUpdateMode(QtWidgets.QGraphicsView.BoundingRectViewportUpdate)
self.setRenderHint(QtGui.QPainter.Antialiasing)
self.filter = FilterGraphItem()
self.scene().addItem(self.filter)
self.measuringBoxes: list = []
def update_measure_boxes(self, viewItems: list) -> None:
self._remove_measure_boxes()
for item in viewItems:
self.measuringBoxes.append(item)
self.scene().addItem(item)
def _remove_measure_boxes(self) -> None:
for item in self.measuringBoxes:
self.scene().removeItem(item)
self.measuringBoxes = []
class FilterGraphItem(QtWidgets.QGraphicsItem):
"""
The Graphical Representation of the actual filter
"""
def __init__(self, filterWidth:float=500, filterHeight:float=500):
super(FilterGraphItem, self).__init__()
self.width = filterWidth
self.height = filterHeight
self.setPos(0, 0)
self.rect = QtCore.QRectF(0, 0, self.width, self.height)
def boundingRect(self) -> QtCore.QRectF:
return self.rect
def paint(self, painter: QtGui.QPainter, option, widget) -> None:
painter.setPen(QtCore.Qt.black)
painter.setBrush(QtCore.Qt.white)
painter.drawRect(self.rect)
painter.setPen(QtCore.Qt.darkGray)
painter.setBrush(QtCore.Qt.lightGray)
painter.drawEllipse(self.rect)
class MeasureBoxGraphItem(QtWidgets.QGraphicsItem):
"""
Displays a box in which particles will be measured
"""
def __init__(self, posX:float=50, posY:float=50, width:float=50, height:float=50) -> None:
super(MeasureBoxGraphItem, self).__init__()
self.posX: float = posX
self.posY: float = posY
self.height: float = height
self.width: float = width
self.setPos(posX, posY)
self.rect = QtCore.QRectF(0, 0, self.width, self.height)
self.setToolTip(f'x0: {round(self.posX)}, y0: {round(self.posY)}, \n'
f'x1: {round(self.posX + self.width)}, y1: {round(self.posY + self.height)}')
def boundingRect(self) -> QtCore.QRectF:
return self.rect
def paint(self, painter, option, widget) -> None:
painter.setBrush(QtCore.Qt.green)
painter.setPen(QtCore.Qt.darkGreen)
painter.drawRects(self.rect)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
filterView = FilterView()
filterView.show()
ret = app.exec_()
\ No newline at end of file
from PyQt5 import QtWidgets
from filterView import FilterView
from measureModes import CrossBoxMode, CrossBoxesControls
class MainView(QtWidgets.QWidget):
def __init__(self):
super(MainView, self).__init__()
self.setWindowTitle('Subsampling Selector')
self.layout: QtWidgets.QVBoxLayout = QtWidgets.QVBoxLayout()
self.setLayout(self.layout)
self.modeSelector: QtWidgets.QComboBox = QtWidgets.QComboBox()
self.measureModes: dict = {}
self.activeMode = None
self.activeModeControl: QtWidgets.QGroupBox = QtWidgets.QGroupBox()
self.controlGroup = QtWidgets.QGroupBox()
self.controlGroupLayout = QtWidgets.QHBoxLayout()
self.controlGroup.setLayout(self.controlGroupLayout)
self.controlGroupLayout.addWidget(QtWidgets.QLabel('Select Subsampling Mode:'))
self.controlGroupLayout.addWidget(self.modeSelector)
self.controlGroupLayout.addWidget(self.activeModeControl)
self.layout.addWidget(self.controlGroup)
self.filterView = FilterView()
self.layout.addWidget(self.filterView)
self._add_measure_modes()
self._switch_to_default_mode()
def _add_measure_modes(self) -> None:
self.modeSelector.addItem('crossSelection')
self.measureModes['crossSelection'] = CrossBoxMode(self.filterView)
def _switch_to_default_mode(self) -> None:
modes: list = list(self.measureModes.keys())
self._activate_mode(modes[0])
def _activate_mode(self, modeName: str) -> None:
self.activeModeControl.setParent(None)
self.controlGroupLayout.removeWidget(self.activeModeControl)
self.activeMode = self.measureModes[modeName]
self.activeModeControl = self.activeMode.get_control_groupBox()
self.controlGroupLayout.insertWidget(2, self.activeModeControl)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
subsampling = MainView()
subsampling.show()
ret = app.exec_()
\ No newline at end of file
from PyQt5 import QtCore, QtWidgets
# import os, sys, inspect
# currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
# parentdir = os.path.dirname(currentdir)
# sys.path.insert(0, parentdir)
# del currentdir, parentdir
from filterView import FilterView, MeasureBoxGraphItem
from geometricOperations import CrossBoxSelector
class MeasureMode(QtCore.QObject):
def __init__(self, relatedFilterView: FilterView):
super(MeasureMode, self).__init__()
self.filterView = relatedFilterView
self.uiControls: QtWidgets.QGroupBox = QtWidgets.QGroupBox()
def get_control_groupBox(self) -> QtWidgets.QGroupBox:
return self.uiControls
def update_measure_viewItems(self) -> None:
raise NotImplementedError
class CrossBoxMode(MeasureMode):
def __init__(self, *args):
super(CrossBoxMode, self).__init__(*args)
self.uiControls = CrossBoxesControls(self)
self.crossBoxGenerator: CrossBoxSelector = CrossBoxSelector(None)
self.update_measure_viewItems()
def update_measure_viewItems(self) -> None:
self.crossBoxGenerator.filterHeight = self.filterView.filter.height
self.crossBoxGenerator.filterWidth = self.filterView.filter.width
self.crossBoxGenerator.numBoxesAcross = int(self.uiControls.numBoxesSelector.currentText())
desiredCoverage: int = self.uiControls.coverageSpinbox.value()
maxCoverage: int = int(self.crossBoxGenerator.get_maximum_achievable_fraction() * 100)
self.uiControls.set_to_max_possible_coverage(maxCoverage)
if desiredCoverage > maxCoverage:
desiredCoverage = maxCoverage
self.crossBoxGenerator.fraction = desiredCoverage / 100
viewItems = []
topLefts: list = self.crossBoxGenerator.get_topLeft_of_boxes()
boxSize = self.crossBoxGenerator.boxSize
for (x, y) in topLefts:
newBox: MeasureBoxGraphItem = MeasureBoxGraphItem(x, y, boxSize, boxSize)
viewItems.append(newBox)
self.filterView.update_measure_boxes(viewItems)
class CrossBoxesControls(QtWidgets.QGroupBox):
"""
Gives a groupbox with the controls for setting up the cross boxes.
"""
def __init__(self, measureModeParent: MeasureMode):
super(CrossBoxesControls, self).__init__()
self.setTitle('Cross Box Controls')
self.measureModeParent = measureModeParent
layout = QtWidgets.QHBoxLayout()
self.setLayout(layout)
layout.addWidget(QtWidgets.QLabel('Number of Boxes across:'))
self.numBoxesSelector = QtWidgets.QComboBox()
self.numBoxesSelector.addItems([str(3), str(5)])
self.numBoxesSelector.currentTextChanged.connect(self._config_changed)
layout.addWidget(self.numBoxesSelector)
layout.addStretch()
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):
self.measureModeParent.update_measure_viewItems()
def set_to_max_possible_coverage(self, maxCoverage:int):
self.coverageSpinbox.setMaximum(maxCoverage)
if maxCoverage < self.coverageSpinbox.value():
self.coverageSpinbox.valueChanged.disconnect()
self.coverageSpinbox.setValue(maxCoverage)
self.coverageSpinbox.valueChanged.connect(self._config_changed)
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Jan 28 19:32:50 2020
@author: luna
"""
class ParticleBinSorter(object):
def __init__(self):
super(ParticleBinSorter, self).__init__()
self.bins = [5, 10, 20, 50, 100, 200, 500]
def sort_particles_into_bins(self, particleList):
particlesInBins = self._get_empty_bins()
for particle in particleList:
binIndex = self._get_binIndex_of_particle(particle)
particlesInBins[binIndex].append(particle)
return particlesInBins
def _get_empty_bins(self):
return [[] for i in range(len(self.bins)+1)]
def _get_binIndex_of_particle(self, particle):
size = particle.getParticleSize()
binIndex = 0
for upperLimit in self.bins:
if size <= upperLimit:
break
else:
binIndex += 1
return binIndex
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Nov 26 17:42:33 2019
@author: brandt
"""
import random
import numpy as np
from helpers import ParticleBinSorter
class SubsamplingMethod(object):
def __init__(self, particleConatainer, desiredFraction: float = 0.2):
super(SubsamplingMethod, self).__init__()
self.particleContainer = particleConatainer
self.fraction = desiredFraction
def apply_subsampling_method(self):
raise NotImplementedError
class RandomSampling(SubsamplingMethod):
#def __init__(self, particleContainer, desiredFraction=0.1):
#super(RandomSampling, self).__init__(particleContainer)
#self.fraction = desiredFraction
def apply_subsampling_method(self):
numOrigParticles = len(self.particleContainer.particles)
numParticles = self._get_number_of_random_particles(numOrigParticles)
subParticles = random.sample(self.particleContainer.particles, numParticles)
return self.fraction, subParticles
def _get_number_of_random_particles(self, numTotalParticles):
return np.int(np.ceil(numTotalParticles * self.fraction))
class IvlevaSubsampling(SubsamplingMethod):
def __init__(self, particleContainer, sigma=1.65, mpFraction=0.01, errorMargin=0.1):
super(IvlevaSubsampling, self).__init__(particleContainer)
self.sigma = sigma
self.estimatedMPFraction = mpFraction
self.errorMargin = errorMargin
def apply_subsampling_method(self):
N = self.particleContainer.getNumberOfParticles()
numParticlesMeasured = self._get_ivleva_fraction(N)
subParticles = random.sample(self.particleContainer.particles, numParticlesMeasured)
fractionMeasured = numParticlesMeasured/N
return fractionMeasured, subParticles
def _get_ivleva_fraction(self, N):
P = self.estimatedMPFraction
e = P * self.errorMargin
numParticlesMeasured = np.ceil(P*(1 - P) / (e**2/self.sigma**2 + P*(1-P)/N))
return np.int(numParticlesMeasured)
class SizeBinFractioning(SubsamplingMethod):
def __init__(self, particleConatiner, desiredfraction: float = 0.2):
super(SizeBinFractioning, self).__init__(particleConatiner, desiredfraction)
self.sorter: ParticleBinSorter = ParticleBinSorter()
def apply_subsampling_method(self):
subParticlesPerBin: list = self._get_subParticles_per_bin(self.particleContainer.particles)
subParticles: list = []
for subParticleList in subParticlesPerBin:
for particle in subParticleList:
subParticles.append(particle)
return self.fraction, subParticles
def _get_subParticles_per_bin(self, particleList: list):
particlesInBins: list = self.sorter.sort_particles_into_bins(particleList)
subParticlesPerBin: list = []
for particles in particlesInBins:
numParticlesInBin: int = len(particles)
numSubParticlesPerBin:int = np.int(np.round(numParticlesInBin * self.fraction))
if numSubParticlesPerBin == 0 and numParticlesInBin > 0:
numSubParticlesPerBin = 1
subParticlesInBin: list = random.sample(particles, numSubParticlesPerBin)
subParticlesPerBin.append(subParticlesInBin)
return subParticlesPerBin
class SelectSquaresFromFilter(SubsamplingMethod):
def __init__(self, particleContainer, desiredFraction):
super(SelectSquaresFromFilter, self).__init__(particleContainer)
self.fraction = desiredFraction
import numpy as np
import matplotlib.pyplot as plt
import time
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
from gepard import dataset
from methods import IvlevaSubsampling, RandomSampling, SizeBinFractioning
from helpers import ParticleBinSorter
from evaluation import ResultComparer
fname: str = r'C:\Users\xbrjos\Desktop\temp MP\190313_Soil_5_A_50_5_1_50_1\190313_Soil_5_A_50_5_1_50_1.pkl'
# fname: str = r'C:\Users\xbrjos\Desktop\temp MP\190326_MCII_WWTP_SB_50_2\190326_MCII_WWTP_SB_50_2.pkl'
# fname: str = r'C:\Users\xbrjos\Desktop\temp MP\190326_MCII_WWTP_SB_50_1\190326_MCII_WWTP_SB_50_1.pkl'
# fname: str = r'C:\Users\xbrjos\Desktop\temp MP\KWS_CT_3_ds1_all_10_2\KWS_CT_3_ds1_all_10_2.pkl' #legacy convert not working..
# fname: str = r'C:\Users\xbrjos\Desktop\temp MP\190201_BSB_Stroomi_ds2_R1_R2_50\190201_BSB_Stroomi_ds2_R1_R2_50.pkl' #zvalues image missing, legacy convert fails..
dset = dataset.loadData(fname)
print('loaded dataset')
pc = dset.particleContainer
origParticles = pc.particles
resultComparer = ResultComparer()
numOrigMP = resultComparer._get_number_of_MP_particles(origParticles)
print(f'orig particles: {len(origParticles)}, of which are mp: {numOrigMP}')
# ivlevaSampling = IvlevaSubsampling(pc)
# ivlevaFraction, ivlevaParticles = ivlevaSampling.apply_subsampling_method()
t0 = time.time()
fractions = np.arange(0.05, .55, 0.05)
errors = []
binErrors = []
numIterations = 1000
for fraction in fractions:
print('random sampling, fraction:', fraction)
# randomSampling = RandomSampling(pc, desiredFraction=fraction)
randomSampling = SizeBinFractioning(pc, fraction)
iterErrors = []
binIterErrors = []
for _ in range(numIterations):
randomFraction, randomParticles = randomSampling.apply_subsampling_method()
iterErrors.append(resultComparer._get_mp_count_error(origParticles, randomParticles, randomFraction))
bins, errorsPerBin = resultComparer._get_mp_count_error_per_bin(origParticles, randomParticles, randomFraction)
binIterErrors.append(errorsPerBin)
errors.append(round(np.mean(iterErrors)*100)) #from fraction to %
fractionBinErrors = []
for binIndex in range(len(bins)+1):
binError = round(np.mean([binIterErrors[i][binIndex] for i in range(numIterations)]) * 100)
fractionBinErrors.append(binError)
binErrors.append(fractionBinErrors)
print('random sampling took', np.round(time.time()-t0, 2), 'seonds')
binLowerLimits = bins.copy()
binLowerLimits.insert(0, 0)
plt.subplot(121)
plt.plot(fractions, errors)
# plt.title(f'Random Sampling, averaged from {numIterations} trials, orig particle count: {len(origParticles)}')
plt.xlabel('Fraction measured')
plt.ylabel('Average error in MP particle count (%)')
plt.subplot(122)
for fracMeas, curBinErrors in zip(fractions, binErrors):
plt.plot(binLowerLimits, curBinErrors, label=np.round(fracMeas, 1))
# plt.title('Error in MP count (%) per size bin')
plt.xlabel('particle size')
plt.ylabel('Average error in MP particle count (%)')
plt.legend()
plt.show()
# sizeBinSampling = SizeBinFractioning(pc)
# sizeBinParticles = sizeBinSampling.apply_subsampling_method()
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 22 13:58:25 2020
@author: luna
"""
import unittest
import random
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
import gepard
from gepard.analysis.particleAndMeasurement import Particle, Measurement
from evaluation import ResultComparer
class TestResultComparer(unittest.TestCase):
def setUp(self):
self.resultComparer = ResultComparer()
def test_get_error_per_bin(self):
def get_full_and_sub_particles(particleSizes, numParticlesPerSizeFull, numParticlesPerSizeSub):
fullParticles = []
subParticles = []
for particleSize in particleSizes:
for _ in range(numParticlesPerSizeFull):
mpParticle = self._get_MP_particle()
mpParticle.longSize = mpParticle.shortSize = particleSize
fullParticles.append(mpParticle)
for _ in range(numParticlesPerSizeSub):
mpParticle = self._get_MP_particle()
mpParticle.longSize = mpParticle.shortSize = particleSize
subParticles.append(mpParticle)
return fullParticles, subParticles
binSizes = [5, 10, 20, 50, 100, 200, 500]
particleSizes = [upperLimit - 1 for upperLimit in binSizes]
numParticlesPerSizeFull = 20
numParticlesPerSizeSub = 10
fullParticles, subParticles = get_full_and_sub_particles(particleSizes, numParticlesPerSizeFull, numParticlesPerSizeSub)
#assume everything was measured
bins, mpCountErrorsPerBin = self.resultComparer._get_mp_count_error_per_bin(fullParticles, subParticles, 1.)
for binIndex, binError in enumerate(mpCountErrorsPerBin):
if binIndex <= 6:
self.assertEqual(binError, 0.5)
else: #it's the last and largest bin, no particles where added there
self.assertEqual(binError, 0)
#assume only 50 % was measured
bins, mpCountErrorsPerBin = self.resultComparer._get_mp_count_error_per_bin(fullParticles, subParticles, 0.5)
for binIndex, binError in enumerate(mpCountErrorsPerBin):
self.assertEqual(binError, 0)
def test_get_number_of_MP_particles(self):
mpParticles = self._get_MP_particles(5)
numMPParticles = len(mpParticles)
nonMPparticles = self._get_non_MP_particles(50)
allParticles = mpParticles + nonMPparticles
calculatedNumMPParticles = self.resultComparer._get_number_of_MP_particles(allParticles)
self.assertEqual(numMPParticles, calculatedNumMPParticles)
def test_get_mp_count_error(self):
mpParticles1 = self._get_MP_particles(20)
nonMPparticles1 = self._get_non_MP_particles(20)
origParticles = mpParticles1 + nonMPparticles1
mpParticles2 = self._get_MP_particles(30)
estimateParticles = mpParticles2 + nonMPparticles1
mpCountError = self.resultComparer._get_mp_count_error(origParticles, estimateParticles, 1.0)
self.assertEqual(mpCountError, 0.5)
mpParticles2 = self._get_MP_particles(20)
estimateParticles = mpParticles2 + nonMPparticles1
mpCountError = self.resultComparer._get_mp_count_error(origParticles, estimateParticles, 1.0)
self.assertEqual(mpCountError, 0)
mpCountError = self.resultComparer._get_mp_count_error(origParticles, estimateParticles, 0.5)
self.assertEqual(mpCountError, 1.0)
def test_get_error_from_values(self):
exact, estimate = 100, 90
error = self.resultComparer._get_error_from_values(exact, estimate)
self.assertEqual(error, 0.1)
exact, estimate = 100, 110
error = self.resultComparer._get_error_from_values(exact, estimate)
self.assertEqual(error, 0.1)
exact, estimate = 100, 50
error = self.resultComparer._get_error_from_values(exact, estimate)
self.assertEqual(error, 0.5)
exact, estimate = 100, 150
error = self.resultComparer._get_error_from_values(exact, estimate)
self.assertEqual(error, 0.5)
def _get_MP_particles(self, numParticles):
mpParticles = []
for _ in range(numParticles):
mpParticles.append(self._get_MP_particle())
return mpParticles
def _get_non_MP_particles(self, numParticles):
nonMPParticles = []
for _ in range(numParticles):
nonMPParticles.append(self._get_non_MP_particle())
return nonMPParticles
def _get_MP_particle(self):
polymerNames = ['Poly (methyl methacrylate',
'Polyethylene',
'Silicone rubber',
'PB15',
'PY13',
'PR20']
polymName = random.sample(polymerNames, 1)[0]
newParticle = Particle()
newMeas = Measurement()
newMeas.setAssignment(polymName)
newParticle.addMeasurement(newMeas)
return newParticle
def _get_non_MP_particle(self):
newParticle = Particle()
newParticle.addMeasurement(Measurement())
return newParticle
if __name__ == '__main__':
unittest.main()
\ No newline at end of file
import unittest
from geometricOperations import CrossBoxSelector
class TestSelectBoxes(unittest.TestCase):
def setUp(self) -> None:
self.crossBoxSelector = CrossBoxSelector(None)
def test_get_topLeft_of_boxes(self):
self.crossBoxSelector.filterWidth = self.crossBoxSelector.filterHeight = 100
self.crossBoxSelector.fraction = 0.1