Commit 6d4cec73 authored by Josef Brandt's avatar Josef Brandt

Timing-Decorator, filter Rotation

parent 5a65802d
......@@ -149,7 +149,6 @@ class ChemometricSubsampling(SubsamplingMethod):
numAmpPoints = numClusteredPoints + numNoisePoints*noiseAmpFactor
fractionPerCluster = np.clip(numPointsToSelect / numAmpPoints, 0.0, 1.0)
print('fractionPerCluster, self.fraction', fractionPerCluster, self.fraction)
tooFewPoints = numPointsToSelect < len(individualLabels)
......
import numpy as np
cimport numpy as np
cimport cython
DTYPE = np.float
ctypedef np.float_t DTYPE_t
ctypedef np.int32_t INT32_t
def rotate_contour_around_point(np.ndarray[DTYPE_t, ndim=3] contour, np.ndarray[DTYPE_t, ndim=1] refPoint, np.float angleDegree):
# def rotate_contour_around_point(contour: np.ndarray, refPoint: tuple, angleDegree: float) -> np.ndarray:
"""
Rotates a point around another one...
:param contour: Array of points to be rotated, [:, 0, 0] = x, [:, 0, 1] = y
:param refPoint: The referemce point around which the first point is rotated, tuple of x and y
:param angleDegree: The angle in degree to rotate (counter-clockwise)
:return: Array of the rotated point, [:, 0, 0] = x, [:, 0, 1] = y
"""
cdef int i
cdef double theta, sin, cos, x, y
cdef np.ndarray[DTYPE_t, ndim=3] newContour
theta = np.deg2rad(angleDegree)
sin = np.sin(theta)
cos = np.cos(theta)
newContour = np.zeros_like(contour, dtype=np.float)
for i in range(contour.shape[0]):
x: float = cos * (contour[i, 0, 0]-refPoint[0]) - sin * (contour[i, 0, 1]-refPoint[1]) + refPoint[0]
y: float = sin * (contour[i, 0, 0]-refPoint[0]) + cos * (contour[i, 0, 1]-refPoint[1]) + refPoint[1]
newContour[i, 0, 0] = x
newContour[i, 0, 1] = y
return newContour
# try:
from setuptools import setup
from setuptools import Extension
from Cython.Build import cythonize
import numpy as np
import sys
if len(sys.argv) == 1:
sys.argv.append("build_ext")
sys.argv.append("--inplace")
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()]
)
\ No newline at end of file
......@@ -161,7 +161,6 @@ class SampleResult(object):
"""
if not self.has_attribute(newAttribute):
self.attributes.append(newAttribute)
print(f'sample {self.filepath} has now attribute {newAttribute}')
def has_any_attribute(self, listOfAttributes: list) -> bool:
hasAttr: bool = False
......
from PyQt5 import QtGui, QtWidgets, QtCore
import numpy as np
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
import gepard
from gepard import dataset
import helpers
import numpy as np
from cythonModules import rotateContour as rc
class FilterView(QtWidgets.QGraphicsView):
......@@ -14,6 +15,7 @@ class FilterView(QtWidgets.QGraphicsView):
self.setWindowTitle('FilterView')
self.dataset: dataset.DataSet = None
self.rotation: int = 0
scene = QtWidgets.QGraphicsScene(self)
scene.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex)
......@@ -47,6 +49,21 @@ 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.float)
for particle in self.dataset.particleContainer.particles:
contour: np.ndarray = particle.contour.astype(np.float)
particle.contour = rc.rotate_contour_around_point(contour, center, angle)
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:
......
......@@ -25,14 +25,24 @@ class MainView(QtWidgets.QWidget):
loadDsetBtn = QtWidgets.QPushButton('Load Dataset')
loadDsetBtn.released.connect(self._load_dataset)
self.rotationSpinBox = QtWidgets.QSpinBox()
self.rotationSpinBox.setMinimum(0)
self.rotationSpinBox.setMaximum(359)
self.rotationSpinBox.setValue(0)
self.rotationSpinBox.setMaximumWidth(50)
self.rotationSpinBox.valueChanged.connect(self._update_fiter_rotation)
self.controlGroup = QtWidgets.QGroupBox()
self.controlGroupLayout = QtWidgets.QHBoxLayout()
self.controlGroup.setLayout(self.controlGroupLayout)
self.controlGroupLayout.addWidget(loadDsetBtn)
self.controlGroupLayout.addWidget(QtWidgets.QLabel('Filter Rotation'))
self.controlGroupLayout.addWidget(self.rotationSpinBox)
self.controlGroupLayout.addWidget(QtWidgets.QLabel('Select Subsampling Mode:'))
self.controlGroupLayout.addWidget(self.modeSelector)
self.controlGroupLayout.addWidget(self.activeModeControl)
self.controlGroupLayout.addStretch()
self.layout.addWidget(self.controlGroup)
self.filterView = FilterView()
......@@ -62,10 +72,11 @@ class MainView(QtWidgets.QWidget):
self.activeMode = requestedMode
self.activeModeControl = self.activeMode.get_control_groupBox()
self.controlGroupLayout.insertWidget(2, self.activeModeControl)
self.controlGroupLayout.insertWidget(3, self.activeModeControl)
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] != '':
......@@ -91,6 +102,10 @@ class MainView(QtWidgets.QWidget):
self.filterView.update_from_dataset(dset)
self.activeMode.update_measure_viewItems()
def _update_fiter_rotation(self):
self.filterView.update_rotation(self.rotationSpinBox.value())
self.activeMode.send_measuredParticles_to_filterview()
if __name__ == '__main__':
import sys
......
......@@ -9,6 +9,7 @@ class MeasureMode(QtCore.QObject):
self.filterView: FilterView = relatedFilterView
self.uiControls: QtWidgets.QGroupBox = QtWidgets.QGroupBox()
self.boxGenerator: BoxSelectionSubsamplingMethod = None
self.subParticles: list = []
def get_control_groupBox(self) -> QtWidgets.QGroupBox:
return self.uiControls
......@@ -16,7 +17,7 @@ class MeasureMode(QtCore.QObject):
def update_measure_viewItems(self) -> None:
raise NotImplementedError
def _send_measuredParticles_to_filterview(self) -> None:
def send_measuredParticles_to_filterview(self) -> None:
if self.boxGenerator.particleContainer is not None:
subParticles = self.boxGenerator.apply_subsampling_method()
self.filterView.update_measured_particles(subParticles)
......@@ -44,7 +45,7 @@ class CrossBoxMode(MeasureMode):
topLefts: list = self.boxGenerator.get_topLeft_of_boxes()
boxSize = self.boxGenerator.boxSize
self.filterView.update_measure_boxes(topLefts, boxSize)
self._send_measuredParticles_to_filterview()
self.send_measuredParticles_to_filterview()
class CrossBoxesControls(QtWidgets.QGroupBox):
......@@ -103,7 +104,7 @@ class SpiralBoxMode(MeasureMode):
topLefts: list = self.boxGenerator.get_topLeft_of_boxes()
boxSize = self.boxGenerator.boxSize
self.filterView.update_measure_boxes(topLefts, boxSize)
self._send_measuredParticles_to_filterview()
self.send_measuredParticles_to_filterview()
class SpiralBoxControls(QtWidgets.QGroupBox):
......
......@@ -3,24 +3,42 @@ import numpy as np
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
from gepard import dataset
import time
def timingDecorator(callingFunction):
"""
A wrapper function for timing the duration of the given function.
:param callingFunction:
:return: wrapped function
"""
def wrapper(*args, **kwargs):
t0 = time.time()
ret = callingFunction(*args, **kwargs)
print(f'{callingFunction.__name__} took {np.round(time.time()-t0, 2)} seconds')
return ret
return wrapper
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 _ in range(len(self.bins)+1)]
def _get_binIndex_of_particle(self, particle):
size = particle.getParticleSize()
binIndex = 0
......@@ -114,7 +132,7 @@ def get_polygon_area(polygon: QtGui.QPolygonF) -> float:
return area
def get_filterDimensions_from_dataset(dataset) -> tuple:
def get_filterDimensions_from_dataset(dataset: dataset.DataSet) -> tuple:
"""
Processes the datasets boundary items to calculate diameter and offset (coord system offset of circular filter
with respect to actual dataset). This is used to set circular filter dimensions to use in the geometric
......
import unittest
import numpy as np
from cythonModules import rotateContour as rc
class CythonTester(unittest.TestCase):
def test_rotate_contour(self):
contour: np.ndarray = np.array([[[0, 5]],
[[5, 5]],
[[5, 0]]], dtype=np.float)
refPoint: np.ndarray = np.array([0, 0], dtype=np.float)
angle: float = 90.0
newContour: np.ndarray = rc.rotate_contour_around_point(contour, refPoint, angle)
self.assertAlmostEqual(newContour[0, 0, 0], -5)
self.assertAlmostEqual(newContour[0, 0, 1], 0)
self.assertAlmostEqual(newContour[1, 0, 0], -5)
self.assertAlmostEqual(newContour[1, 0, 1], 5)
self.assertAlmostEqual(newContour[2, 0, 0], 0)
self.assertAlmostEqual(newContour[2, 0, 1], 5)
angle = 180.0
newContour = rc.rotate_contour_around_point(contour, refPoint, angle)
self.assertAlmostEqual(newContour[0, 0, 0], 0)
self.assertAlmostEqual(newContour[0, 0, 1], -5)
self.assertAlmostEqual(newContour[1, 0, 0], -5)
self.assertAlmostEqual(newContour[1, 0, 1], -5)
self.assertAlmostEqual(newContour[2, 0, 0], -5)
self.assertAlmostEqual(newContour[2, 0, 1], 0)
angle = 270.0
newContour = rc.rotate_contour_around_point(contour, refPoint, angle)
self.assertAlmostEqual(newContour[0, 0, 0], 5)
self.assertAlmostEqual(newContour[0, 0, 1], 0)
self.assertAlmostEqual(newContour[1, 0, 0], 5)
self.assertAlmostEqual(newContour[1, 0, 1], -5)
self.assertAlmostEqual(newContour[2, 0, 0], 0)
self.assertAlmostEqual(newContour[2, 0, 1], -5)
refPoint = np.array([5, 5], dtype=np.float)
angle: float = 90.0
newContour = rc.rotate_contour_around_point(contour, refPoint, angle)
self.assertAlmostEqual(newContour[0, 0, 0], 5)
self.assertAlmostEqual(newContour[0, 0, 1], 0)
self.assertAlmostEqual(newContour[2, 0, 0], 10)
self.assertAlmostEqual(newContour[2, 0, 1], 5)
angle = 180.0
newContour = rc.rotate_contour_around_point(contour, refPoint, angle)
self.assertAlmostEqual(newContour[0, 0, 0], 10)
self.assertAlmostEqual(newContour[0, 0, 1], 5)
self.assertAlmostEqual(newContour[2, 0, 0], 5)
self.assertAlmostEqual(newContour[2, 0, 1], 10)
angle = 270.0
newContour = rc.rotate_contour_around_point(contour, refPoint, angle)
self.assertAlmostEqual(newContour[0, 0, 0], 5)
self.assertAlmostEqual(newContour[0, 0, 1], 10)
self.assertAlmostEqual(newContour[2, 0, 0], 0)
self.assertAlmostEqual(newContour[2, 0, 1], 5)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment