Commit 7d28e523 authored by JosefBrandt's avatar JosefBrandt

Merge branch 'RefactoringAnalysisModules'

parents 8fc15b1e 582761bd
__pycache__/
gepard\.cfg
analysis/database_config\.txt
*.so
*.c
external/build/
.idea/
......@@ -18,18 +18,17 @@ You should have received a copy of the GNU General Public License
along with this program, see COPYING.
If not, see <https://www.gnu.org/licenses/>.
"""
from PyQt5 import QtCore, QtWidgets, QtGui
from sampleview import SampleView
from scalebar import ScaleBar
from ramancom.ramancontrol import defaultPath
from ramancom.ramanSwitch import RamanSwitch
from colorlegend import ColorLegend
import os
from PyQt5 import QtCore, QtWidgets, QtGui
from .sampleview import SampleView
from .scalebar import ScaleBar
from .ramancom.ramancontrol import defaultPath
from .ramancom.ramanSwitch import RamanSwitch
from .analysis.colorlegend import ColorLegend
class MeasureParticleWindow(QtWidgets.QMainWindow):
class GEPARDMainWindow(QtWidgets.QMainWindow):
def __init__(self, logpath):
super(MeasureParticleWindow, self).__init__()
super(GEPARDMainWindow, self).__init__()
self.setWindowTitle("GEPARD")
self.resize(900, 700)
......@@ -101,13 +100,24 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
fileName = QtWidgets.QFileDialog.getSaveFileName(self, "Create New Project",
defaultPath, "*.pkl")[0]
if fileName:
if fileName.find(' ') < 0:
isValid, msg = self.testFilename(fileName)
if isValid:
self.fname = str(fileName)
self.view.new(self.fname)
self.scalingChanged(1.)
else:
QtWidgets.QMessageBox.critical(self, "Error", "File path must not contain spaces.")
QtWidgets.QMessageBox.critical(self, "Error", msg)
@QtCore.pyqtSlot()
def testFilename(self, fileName):
if self.view.ramanctrl.name == 'RenishawCOM': #the renishawCom does not allow Spaces within filePath
if fileName.find(' ') == 0:
return False, "File path must not contain spaces."
else:
return True, ""
else:
return True, ""
@QtCore.pyqtSlot()
def about(self):
QtWidgets.QMessageBox.about(self, 'GEPARD',
......@@ -116,7 +126,7 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
def createActions(self):
fname = os.path.join(os.path.split(__file__)[0],
os.path.join("data","brand.png"))
os.path.join('data', 'brand.png'))
self.aboutAct = QtWidgets.QAction(QtGui.QIcon(fname),
"About Particle Measurment", self)
self.aboutAct.triggered.connect(self.about)
......@@ -125,7 +135,7 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
self.openAct.setShortcut("Ctrl+O")
self.openAct.triggered.connect(self.open)
self.importAct = QtWidgets.QAction("&Import Project...", self)
self.importAct = QtWidgets.QAction("&Import Zeiss Project...", self)
self.importAct.setShortcut("Ctrl+I")
self.importAct.triggered.connect(self.importProject)
......@@ -188,12 +198,23 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
self.snapshotAct = QtWidgets.QAction("Save Screenshot", self)
self.snapshotAct.triggered.connect(self.view.takeScreenshot)
self.snapshotAct.setDisabled(True)
self.configRamanCtrlAct = QtWidgets.QAction("Configure Raman Control", self)
self.configRamanCtrlAct.triggered.connect(self.view.configureRamanControl)
if self.view.simulatedRaman:
self.configRamanCtrlAct.setDisabled(True)
self.noOverlayAct = QtWidgets.QAction("&No Overlay", self)
self.selOverlayAct = QtWidgets.QAction("&Selected Overlay", self)
self.fullOverlayAct = QtWidgets.QAction("&Full Overlay", self)
self.transpAct = QtWidgets.QAction("&Transparent Overlay", self)
self.hideLabelAct = QtWidgets.QAction('&Hide Spectra Numbers', self)
self.darkenAct = QtWidgets.QAction("&Darken Image", self)
self.seedAct = QtWidgets.QAction("&Set Color Seed", self)
for act in [self.noOverlayAct, self.selOverlayAct, self.fullOverlayAct, self.hideLabelAct, self.transpAct, self.darkenAct, self.seedAct]:
act.setDisabled(True)
def updateModes(self, active=None, maxenabled=None):
ose, osc, pde, pdc, rse, rsc, pae, pac = [False]*8
if maxenabled=="OpticalScan":
......@@ -273,6 +294,17 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
self.toolsMenu = QtWidgets.QMenu("&Tools")
self.toolsMenu.addAction(self.snapshotAct)
self.toolsMenu.addAction(self.configRamanCtrlAct)
self.dispMenu = QtWidgets.QMenu("&Display", self)
self.overlayActGroup = QtWidgets.QActionGroup(self.dispMenu)
self.overlayActGroup.setExclusive(True)
for act in [self.noOverlayAct, self.selOverlayAct, self.fullOverlayAct]:
self.dispMenu.addAction(act)
self.overlayActGroup.addAction(act)
self.dispMenu.addSeparator()
self.dispMenu.addActions([self.transpAct, self.hideLabelAct, self.darkenAct, self.seedAct])
self.helpMenu = QtWidgets.QMenu("&Help", self)
self.helpMenu.addAction(self.aboutAct)
......@@ -281,9 +313,9 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
self.menuBar().addMenu(self.viewMenu)
self.menuBar().addMenu(self.modeMenu)
self.menuBar().addMenu(self.toolsMenu)
self.menuBar().addMenu(self.dispMenu)
self.menuBar().addMenu(self.helpMenu)
def createToolBar(self):
self.toolbar = QtWidgets.QToolBar("Tools")
self.toolbar.setIconSize(QtCore.QSize(100,50))
......@@ -322,12 +354,10 @@ if __name__ == '__main__':
fp = open(logname, "a")
sys.stderr = fp
sys.stdout = fp
print("starting GEPARD at: " + strftime("%d %b %Y %H:%M:%S", localtime()), flush=True)
print("starting GEPARD at: " + strftime("%d %b %Y %H:%M:%S", localtime()),
flush=True)
meas = MeasureParticleWindow(logpath)
meas.showMaximized()
gepard = GEPARDMainWindow(logpath)
gepard.showMaximized()
ret = app.exec_()
if fp is not None:
fp.close()
\ No newline at end of file
fp.close()
# -*- coding: utf-8 -*-
"""
GEPARD - Gepard-Enabled PARticle Detection
Copyright (C) 2018 Lars Bittrich and Josef Brandt, Leibniz-Institut für
Polymerforschung Dresden e. V. <bittrich-lars@ipfdd.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program, see COPYING.
If not, see <https://www.gnu.org/licenses/>.
"""
import pickle
def loadAssigments(fname):
with open(fname, "rb") as fp:
assignment = pickle.load(fp)
return assignment
def saveAssignments(assignment, fname):
with open(fname, "wb") as fp:
pickle.dump(assignment, fp, protocol=-1)
class DBAssignment(object):
def __init__(self):
self.filename = None
self.assignments = []
def setFileName(self, fname):
self.filename = fname
def save(self):
saveAssignments(self, self.filename)
def hasAssignment(self, polymerName):
polymIsPresent = False
for assignment in self.assignments:
if assignment.polymerName == polymerName:
polymIsPresent = True
break
return polymIsPresent
def getAssignment(self, polymerName):
for assignment in self.assignments:
if assignment.polymerName == polymerName:
return assignment
def createNewAssignment(self, polymerName):
self.assignments.append(Assignment(polymerName))
def updateAssignment(self, polymerName, result, catRes, indic_paint):
for assignment in self.assignments:
if assignment.polymerName == polymerName:
assignment.update(result, catRes, indic_paint)
return
class Assignment(object):
def __init__(self, polymerName):
self.polymerName = polymerName
self.result = None
self.categorizedResult = None
self.indication_paint = None
def update(self, result, catRes, indic_paint):
self.result = result
self.categorizedResult = catRes
self.indication_paint = indic_paint
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -20,10 +20,25 @@ If not, see <https://www.gnu.org/licenses/>.
"""
from PyQt5 import QtCore, QtWidgets, QtGui
import numpy as np
import random
import colorsys
def getColorFromNameWithSeed(name, seed, base255=True):
random.seed(seed + name)
hue = random.random()
random.seed((seed + name)*2)
saturation = random.random()/4 + 0.75 #i.e., between 0.75 and 1
random.seed((seed + name)*3)
value = random.random()/5 + 0.8 #i.e., between 0.8 and 1
color = colorsys.hsv_to_rgb(hue, saturation, value)
if base255:
color = list(color)
for i in range(3):
color[i] = np.round(color[i]*255)
color = tuple(color)
return color
WX, WY = 1024, 200
class ColorLegend(QtWidgets.QMdiSubWindow):
def __init__(self, parent=None):
super().__init__(parent)
......@@ -40,7 +55,6 @@ class ColorLegend(QtWidgets.QMdiSubWindow):
def setTextColorItems(self, items):
for text, color in items:
print(text, color)
assert type(text)==str or type(text)==np.str_, "items must be tuples of text and QColor"
assert type(color)==QtGui.QColor or type(color)==QtCore.Qt.GlobalColor, "items must be tuples of text and QColor"
self.items = items
......@@ -109,6 +123,4 @@ class ColorLegend(QtWidgets.QMdiSubWindow):
y0 = index*(fontSize+spacer) + (fontSize - tileSize)/2 +spacer/2
qp.drawRect(x0, y0, tileSize, tileSize)
qp.end()
\ No newline at end of file
qp.end()
\ No newline at end of file
......@@ -27,24 +27,26 @@ with permission from github user CJ Carey (perimosocordiae)
from PyQt5 import QtWidgets, QtCore
import numpy as np
import sys
import dill
import dill #TODO: Make it run with pickle... Having two different methods is not so sensefull...
import os
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import functools
from scipy.linalg import solveh_banded
from pathlib import Path
class DataBaseWindow(QtWidgets.QMainWindow):
def __init__(self, parent):
super(DataBaseWindow, self).__init__()
self.parent = parent
self.path = os.path.join(Path.home(), 'gepard', 'databases')
logpath = QtCore.QStandardPaths.writableLocation(
QtCore.QStandardPaths.AppLocalDataLocation)
self.path = os.path.join(logpath, 'databases')
self.importPath = self.path
if not os.path.exists(self.path):
os.mkdir(self.path)
os.makedirs(self.path)
self.activeDatabase = None
self.activeSpectrum = None
self.activeSpectrumName = None
......@@ -314,16 +316,14 @@ class DataBaseWindow(QtWidgets.QMainWindow):
self.removeSpecBtn.setText('Remove {}'.format(self.activeSpectrumName))
self.removeSpecBtn.setDisabled(False)
def save(self):
def save(self, showMessage=True):
for index, db in enumerate(self.databases):
# pickling_on = open(db.title+'.dbpkl', 'wb')
# pickle.dump(db, pickling_on)
# pickling_on.close()
savename = os.path.join(self.path, db.title+'.db')
with open(savename, 'wb') as f:
dill.dump(db, f)
QtWidgets.QMessageBox.about(self, 'Done.', 'Saved {} database(s)'.format(len(self.databases)))
if showMessage:
QtWidgets.QMessageBox.about(self, 'Done.', 'Saved {} database(s)'.format(len(self.databases)))
def updateDBSelectorList(self):
self.db_selector.clear()
......@@ -336,7 +336,6 @@ class DataBaseWindow(QtWidgets.QMainWindow):
self.db_selector.setCurrentText(self.activeDatabase.title)
def selectDataBase(self, refreshParent=False):
# if not self.noDBFound:
if len(self.databases) > 0:
self.activeDatabaseIndex = self.db_selector.currentIndex()
self.activeDatabase = self.databases[self.activeDatabaseIndex]
......@@ -349,13 +348,7 @@ class DataBaseWindow(QtWidgets.QMainWindow):
self.parent.populateRefSelector()
def closeEvent(self, event):
# response = QtWidgets.QMessageBox.question(self, 'Warning', 'Exit without saving?', QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
# if response == QtWidgets.QMessageBox.Yes:
# if self.parent is not None:
# self.parent.setDisabled(False)
# event.accept()
# else:
# event.ignore()
self.save(showMessage=False)
if self.parent is not None:
self.parent.setDisabled(False)
......@@ -423,8 +416,6 @@ class BaseLineCorrect(QtWidgets.QDialog):
for i in range(len(spectra)):
spectra[i][:, 1] = self.origspectra[i][:, 1].copy() - self.als_baseline(self.origspectra[i][:, 1].copy(), asymmetry_param=self.asymSpinBox.value(),
smoothness_param=self.smoothSpinBox.value(), max_iters = self.iterSpinBox.value())
# self.newSpectra = spectra.copy()
# self.parent.drawSpectrum(spectra[self.parent.activeSpectrumIndex], self.parent.activeSpectrumName)
self.saveBtn.setDisabled(False)
def als_baseline(self, intensities, asymmetry_param=0.05, smoothness_param=1e4,
......@@ -450,27 +441,17 @@ class BaseLineCorrect(QtWidgets.QDialog):
if conv < conv_thresh:
break
w = new_w
# else:
# print( 'ALS did not converge in %d iterations' % max_iters)
else:
print( 'ALS did not converge in %d iterations' % max_iters)
return z
def save(self):
# self.parent.databases[self.parent.activeDatabaseIndex].spectra = self.spectra
# self.parent.activeDatabase = self.parent.databases[self.parent.activeDatabaseIndex]
# self.parent.activeSpectrum = self.parent.activeDatabase.spectra[self.parent.activeSpectrumIndex]
# self.parent.drawSpectrum(self.parent.activeSpectrum, self.parent.activeSpectrumName)
self.close()
def cancel(self):
self.close()
def closeEvent(self, event):
if self.parent is not None:
self.parent.setDisabled(False)
# self.parent.drawSpectrum(self.parent.activeSpectrum, self.parent.activeSpectrumName)
class WhittakerSmoother(object):
def __init__(self, signal, smoothness_param, deriv_order=1):
......@@ -546,18 +527,4 @@ class CropSpectra(QtWidgets.QDialog):
def closeEvent(self, event):
if self.parent is not None:
self.parent.setDisabled(False)
event.accept()
def main():
global dbWin
#start Application
app = QtWidgets.QApplication(sys.argv)
dbWin = DataBaseWindow(None)
app.exec_()
if __name__ == '__main__':
main()
\ No newline at end of file
event.accept()
\ No newline at end of file
This diff is collapsed.
# -*- coding: utf-8 -*-
"""
GEPARD - Gepard-Enabled PARticle Detection
Copyright (C) 2018 Lars Bittrich and Josef Brandt, Leibniz-Institut für
Polymerforschung Dresden e. V. <bittrich-lars@ipfdd.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program, see COPYING.
If not, see <https://www.gnu.org/licenses/>.
"""
from PyQt5 import QtWidgets
import numpy as np
import pandas as pd
import os
import sys
class ExpExcelDialog(QtWidgets.QDialog):
def __init__(self, dataset):
super(ExpExcelDialog, self).__init__()
self.setWindowTitle('Export Options')
self.setGeometry(200, 200, 300, 300)
self.layout = QtWidgets.QHBoxLayout()
self.setLayout(self.layout)
self.dataset = dataset
self.particleContainer = dataset.particleContainer
excelvbox = QtWidgets.QVBoxLayout()
excelvbox.addWidget(QtWidgets.QLabel('Select Parameters for Export'))
excelgroup = QtWidgets.QGroupBox("Export to Excel", self)
self.exportOptions = ['Polymer Type (mandatory)', 'Long Size (µm)', 'Short Size (µm)', 'Area (µm²)', 'HQI', 'Size Classes']
self.checkBoxes = []
self.sizeClasses = [5, 10, 20, 50, 100, 1e6]
for index, option in enumerate(self.exportOptions):
self.checkBoxes.append(QtWidgets.QCheckBox(self))
self.checkBoxes[-1].setText(option)
self.checkBoxes[-1].setChecked(True)
if option == 'Polymer Type (mandatory)':
self.checkBoxes[-1].setEnabled(False) #is mandatory!!!
excelvbox.addWidget(self.checkBoxes[-1])
self.xlsFileName = QtWidgets.QLineEdit()
self.xlsFileName.setText('{}_Particle_List'.format(self.dataset.name))
excelvbox.addWidget(QtWidgets.QLabel('Filename:'))
excelvbox.addWidget(self.xlsFileName)
self.exlbtn = QtWidgets.QPushButton('Export to Excel')
self.exlbtn.resize(self.exlbtn.sizeHint())
self.exlbtn.clicked.connect(self.toExcel)
excelvbox.addWidget(self.exlbtn)
excelgroup.setLayout(excelvbox)
self.layout.addWidget(excelgroup)
self.show()
def toExcel(self):
requiredcolumns = []
uniquePolymers = self.particleContainer.getUniquePolymers()
polymers = np.array(self.particleContainer.getListOfParticleAssignments())
sizes = np.array(self.particleContainer.getSizesOfAllParticles())
for box in self.checkBoxes:
if box.isChecked() == True:
if box.text() != 'Size Classes':
requiredcolumns.append(box.text())
if box.text() == 'Long Size (µm)':
longSizes = np.round(sizes)
elif box.text() == 'Short Size (µm)':
shortSizes = np.round(np.array(self.particleContainer.getShortSizesOfAllParticles()))
elif box.text() == 'HQI':
hqis = np.array(self.particleContainer.getListOfHighestHQIs())
elif box.text() == 'Area (µm²)':
areas = np.array(self.particleContainer.getAreasOfAllParticles())
else:
requiredcolumns.append('0 - 5 µm')
requiredcolumns.append('5 - 10 µm')
requiredcolumns.append('10 - 20 µm')
requiredcolumns.append('20 - 50 µm')
requiredcolumns.append('50 - 100 µm')
requiredcolumns.append('> 100 µm')
finalData = np.zeros((len(polymers),len(requiredcolumns)-1))
polymertypes = [""]*len(polymers)
rowindex = 0
for polymer in uniquePolymers:
indices = polymers == polymer
numentries = int(np.sum(indices))
sys.stdout.flush()
for colindex, column in enumerate(requiredcolumns):
if column == 'Polymer Type (mandatory)':
polymertypes[rowindex:rowindex+numentries] = polymers[indices]
if column == 'Long Size (µm)':
finalData[rowindex:rowindex+numentries, colindex-1] = longSizes[indices]
if column == 'Short Size (µm)':
finalData[rowindex:rowindex+numentries, colindex-1] = shortSizes[indices]
if column == 'Area (µm²)':
finalData[rowindex:rowindex+numentries, colindex-1] = areas[indices]
if column == 'HQI':
finalData[rowindex:rowindex+numentries, colindex-1] = hqis[indices]
if '> 100 µm' in requiredcolumns:
##append size classes
numPrevCols = len(requiredcolumns) - 1 - len(self.sizeClasses) #number of previous columns
for tableindex, dataindex in enumerate(np.arange(len(indices))[indices]):
for classindex in range(len(self.sizeClasses)):
upLimit = self.sizeClasses[classindex]
if classindex == 0: lowLimit = 0
else: lowLimit = self.sizeClasses[classindex-1]
curSize = sizes[dataindex]
if curSize > lowLimit and curSize <= upLimit:
finalData[rowindex+tableindex, numPrevCols + classindex] = np.int(1)
else:
finalData[rowindex+tableindex, numPrevCols + classindex] = np.int(0)
rowindex = rowindex + numentries
#dump into excel file
xlsname = os.path.join(self.dataset.path, f'{self.xlsFileName.text()}.xlsx')
print('exporting excel to:\n file name: {} in directory: {}'.format(self.xlsFileName.text(), self.dataset.path))
incr = 1
while os.path.exists(xlsname):
xlsname = os.path.join(self.dataset.path, f'{self.xlsFileName.text()} {incr}.xlsx')
incr += 1
writer = pd.ExcelWriter(xlsname, engine = 'xlsxwriter')
df = pd.DataFrame(finalData, columns=requiredcolumns[1:])
df.insert(0, 'Polymer Type', polymertypes)
df.to_excel(writer, sheet_name = 'Individual Particles', index = False)
if '> 100 µm' in requiredcolumns:
#generate particle statistics report
header = ['0 - 5 µm', '5 - 10 µm', '10 - 20 µm', '20 - 50 µm', '50 - 100 µm', '> 100 µm']
particleclasses = []
for polymer in uniquePolymers:
indices = self.particleContainer.getIndicesOfParticleType(polymer)
sortind = np.searchsorted([5,10,20,50,100], sizes[indices], 'right')
classes = np.bincount(sortind, minlength=6)
particleclasses.append(classes)
particleclasses = np.array(particleclasses)
report = pd.DataFrame(np.array(particleclasses), columns=header,
dtype=int)
report.insert(0, 'Polymer Type', uniquePolymers)
report.insert(len(report.columns), 'Sum total', particleclasses.sum(axis=1))
report.to_excel(writer, sheet_name = 'Particle Statistics', index=False)
writer.save()
self.accept()
QtWidgets.QMessageBox.about(self, 'Particles succesfully exported', 'List saved to\n' + str(xlsname))
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue May 28 20:33:14 2019
@author: brandt
"""
import numpy as np
'''Return Spectra array (First column: Wavenumbers, all other columns, intensities)
and names for all in file contained spectra'''
#TODO: Include sanity checks for correct file format?
def importWITecSpectra(fname):
def firstColumnOnlyHasUniqueNumbers(data):
#this is the case for WITec Spectra sets, but not for Renishaw
if len(np.unique(data[:, 0])) == len(data[:, 0]):
return True
else:
return False
data = np.loadtxt(fname)
names = [f'Spectrum {i+1}' for i in range(data.shape[1]-1)]
if firstColumnOnlyHasUniqueNumbers(data):
return data, names
else:
raise ImportError
def importRenishawSpectra(fname):
data = np.loadtxt(fname)
rawSpectra = data[:, 2:4]
spectraIndices = np.where(rawSpectra[:, 0] == rawSpectra[0, 0])[0]
positions = np.zeros((len(spectraIndices), 2))
spectra = []
names = []
spectra = np.zeros((spectraIndices[1], len(spectraIndices)+1))
spectra[:, 0] = rawSpectra[0:spectraIndices[1], 0]
for i in range(len(spectraIndices)):
names.append(f'Spectrum {i+1}')
positions[i, :] = [data[spectraIndices[i], 0], data[spectraIndices[i], 1]]
if i < len(spectraIndices)-1:
spectra[:, i+1] = rawSpectra[spectraIndices[i]:spectraIndices[i+1], 1]
else:
spectra[:, i+1] = rawSpectra[spectraIndices[i]:, 1]
spectra = np.flipud(spectra)
wavenumbers = spectra[:, 0]
spectra = spectra[:, 1:]
return np.transpose(np.vstack((wavenumbers, spectra))), names
def importPerkinElmerSpectra(fname):
names = []
spectra = []
with open(fname) as fp:
for index, line in enumerate(fp.readlines()):
if index == 0:
for name in line.split(';'):
names.append(name.split('.sp')[0])
elif index > 1:
spectra.append(line.split(';'))
return np.array(spectra, dtype=np.float), names[1:]
This diff is collapsed.
# -*- coding: utf-8 -*-
"""
GEPARD - Gepard-Enabled PARticle Detection
Copyright (C) 2018 Lars Bittrich and Josef Brandt, Leibniz-Institut für
Polymerforschung Dresden e. V. <bittrich-lars@ipfdd.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program, see COPYING.
If not, see <https://www.gnu.org/licenses/>.
"""
import numpy as np
class Particle(object):
def __init__(self):
super(Particle, self).__init__()
self.index = None
self.longSize = np.nan
self.shortSize = np.nan
self.height = None
self.area = None
self.contour = None
self.measurements = []
self.color = None
self.shape = None
self.wasManuallyEdited = False #useful tag for extracting data that can now be considered reliable and obviously was classfiied wrong before by the algorithms
def addMeasurement(self, refToMeasurement):
refToMeasurement.assignedParticle = self
self.measurements.append(refToMeasurement)