From 0b768ad2cce387ac619cb9d1d69af90061c8acca Mon Sep 17 00:00:00 2001 From: JosefBrandt Date: Mon, 24 Jun 2019 07:15:52 +0200 Subject: [PATCH] First phase of refactoring --- analysis/analysisview.py | 195 ++++++++-------- analysis/analysiswidgets.py | 8 +- analysis/database.py | 7 +- analysis/datastats.py | 391 +++++++++++++++++++++++--------- analysis/importSpectra.py | 68 ++++++ analysis/sqlexport.py | 2 +- dataset.py | 65 ++++-- detectionview.py | 25 +- sample_gepard.cfg => gepard.cfg | 0 gepard.py | 22 +- opticalscan.py | 2 +- ramanscanui.py | 12 +- segmentation.py | 22 +- viewitems.py | 4 +- 14 files changed, 562 insertions(+), 261 deletions(-) create mode 100644 analysis/importSpectra.py rename sample_gepard.cfg => gepard.cfg (100%) diff --git a/analysis/analysisview.py b/analysis/analysisview.py index c4dd94c..3170dec 100755 --- a/analysis/analysisview.py +++ b/analysis/analysisview.py @@ -53,11 +53,12 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.setCentralWidget(self.widget) self.parent = parent - + self.dataset = dataset + self.particleContainer = dataset.particleContainer self.datastats = DataStats(dataset) self.editor = ParticleEditor(self.datastats, self) - self.additivePlot = None +# self.additivePlot = None self.importWindow = None self.polymerCheckBoxes = [] @@ -67,8 +68,8 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.currentSpectrumIndex = 0 self.lastSpectrumInFocus = None - self.typeHistogram = ParticleTypeView(self) - self.typeHistogram.indexClicked.connect(self.getAdditivePlot) + self.typeHistogramPlot = ParticleTypeView(self) +# self.typeHistogramPlot.indexClicked.connect(self.getAdditivePlot) self.sizeHistogramCanvas = FigureCanvas(Figure()) sizeHistGroup = QtWidgets.QGroupBox() @@ -106,7 +107,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): splitter1.addWidget(sizeHistGroup) splitter2 = QtWidgets.QSplitter(QtCore.Qt.Horizontal) splitter2.addWidget(splitter1) - splitter2.addWidget(self.typeHistogram) + splitter2.addWidget(self.typeHistogramPlot) splitter2.setSizes([300, 150]) self.navigationGroup = QtWidgets.QGroupBox('Navigate through polymers') @@ -164,32 +165,31 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.hqiSpinBox.setValue(75.0) self.hqiSpinBox.setDecimals(1) self.hqiSpinBox.setMinimum(0) + self.hqiSpinBox.setMaximum(100) + self.hqiSpinBox.setMaximumWidth(45) optionsLayout.addRow(QtWidgets.QLabel('min HQI:'), self.hqiSpinBox) - self.compHqiSpinBox = QtWidgets.QDoubleSpinBox() - self.compHqiSpinBox.setValue(30.0) - self.compHqiSpinBox.setDecimals(1) - self.compHqiSpinBox.setMinimum(0) - self.compHqiSpinBox.setDisabled(True) - optionsLayout.addRow(QtWidgets.QLabel('min component HQI'), self.compHqiSpinBox) +# self.compHqiSpinBox = QtWidgets.QDoubleSpinBox() +# self.compHqiSpinBox.setValue(30.0) +# self.compHqiSpinBox.setDecimals(1) +# self.compHqiSpinBox.setMinimum(0) +# self.compHqiSpinBox.setDisabled(True) +# optionsLayout.addRow(QtWidgets.QLabel('min component HQI'), self.compHqiSpinBox) self.dispResultSpinBox = QtWidgets.QSpinBox() self.dispResultSpinBox.setValue(20) self.dispResultSpinBox.setMinimum(1) - self.dispResultSpinBox.valueChanged.connect(self.updateHistogram) + self.dispResultSpinBox.valueChanged.connect(self.updateHistograms) optionsLayout.addRow(QtWidgets.QLabel('Max. items in display:'), self.dispResultSpinBox) - for spinbox in [self.hqiSpinBox, self.compHqiSpinBox]: - spinbox.setMaximum(100) - spinbox.setMaximumWidth(45) - self.updateBtn = QtWidgets.QPushButton('Update Results') - self.updateBtn.setDisabled(True) + self.updateBtn.clicked.connect(self.applyHQIThresholdToResults) +# self.updateBtn.setDisabled(True) optionsLayout.addRow(self.updateBtn) self.optionsGroup.setLayout(optionsLayout) self.optionsGroup.setMinimumWidth(175) - self.optionsGroup.setDisabled(True) +# self.optionsGroup.setDisabled(True) self.resultScrollarea = QtWidgets.QScrollArea(self) self.resultScrollarea.setFixedWidth(250) @@ -210,25 +210,24 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.resultCheckBoxes.setLayout(self.resultCheckBoxesLayout) self.layout_SArea.addWidget(self.resultCheckBoxes) -# self.layout_SArea.addStretch(1) -# self.menuLayout.addWidget(reloadGroup) self.menuLayout.addWidget(self.optionsGroup) self.menuLayout.addWidget(self.resultScrollarea) self.layout.addLayout(self.menuLayout) self.layout.addLayout(viewLayout) - minHQI = self.datastats.dataset.resultParams['minHQI'] - compHQI = self.datastats.dataset.resultParams['compHQI'] + minHQI = self.dataset.resultParams['minHQI'] +# compHQI = self.dataset.resultParams['compHQI'] if minHQI is not None: self.hqiSpinBox.setValue(minHQI) - self.compHqiSpinBox.setValue(compHQI) +# self.compHqiSpinBox.setValue(compHQI) self.createActions() self.createMenus() - self.updateData() + self.initializeSpectraPlot() + self.applyHQIThresholdToResults() def createActions(self): self.loadTrueMatchAct = QtWidgets.QAction("Load &TrueMatch Results", self) @@ -241,7 +240,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.selOverlayAct = QtWidgets.QAction("&Selected Overlay", self) self.fullOverlayAct = QtWidgets.QAction("&Full Overlay", self) - self.transpAct = QtWidgets.QAction("&Transparent Overlay") + self.transpAct = QtWidgets.QAction("&Transparent Overlay", self) self.transpAct.triggered.connect(self.createPolymerOverlay) self.hideLabelAct = QtWidgets.QAction('&Hide Polymer Numbers', self) @@ -276,7 +275,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.overlayActGroup = QtWidgets.QActionGroup(self.dispMenu) self.overlayActGroup.setExclusive(True) self.overlayActGroup.triggered.connect(self.createPolymerOverlay) - self.overlayActGroup.triggered.connect(self.updateHistogram) + self.overlayActGroup.triggered.connect(self.updateHistograms) for act in [self.noOverlayAct, self.selOverlayAct, self.fullOverlayAct]: self.dispMenu.addAction(act) @@ -312,63 +311,62 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.refSelector.addItems(self.dbWin.activeDatabase.spectraNames) self.refSelector.setDisabled(False) - def updateData(self): - spectra = self.datastats.update() - if spectra is None: - fname = QtWidgets.QFileDialog.getOpenFileName(self, 'Select Spectra File', self.datastats.dataset.path, 'text file (*.txt)')[0] - spectra = self.datastats.loadSpectra(fname) - if spectra is None: - QtWidgets.QMessageBox.critical(self, 'ERROR!', 'spectra file could not be opened with np.loadtxt...') - return + def initializeSpectraPlot(self): #formerly updateData(self).... + self.particleContainer.loadSpectraFromDisk() self.specCanvas.draw() - self.loadParticleData() - - def loadParticleData(self): - #check, if dataset already contains results. Otherwise load them... - if not self.datastats.loadParticleData(): - self.show() - answer = QtWidgets.QMessageBox.question(self, 'Warning', 'No (or inconsistent) spectra results found, please run import dialog.\nPress OK to import or cancel to set to empty.', QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) - if answer == QtWidgets.QMessageBox.Ok: - self.importTrueMatchResults() - elif answer == QtWidgets.QMessageBox.Cancel: - self.datastats.invalidateSpectra() - self.updateBtn.clicked.connect(self.formatResults) - self.formatResults() - else: - self.updateBtn.clicked.connect(self.formatResults) - self.formatResults() +# self.loadParticleData() + +# def loadParticleData(self): +# #check, if dataset already contains results. Otherwise load them... +# if not self.datastats.loadParticleData(): +# self.show() +# answer = QtWidgets.QMessageBox.question(self, 'Warning', 'No (or inconsistent) spectra results found, please run import dialog.\nPress OK to import or cancel to set to empty.', QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) +# if answer == QtWidgets.QMessageBox.Ok: +# self.importTrueMatchResults() +# elif answer == QtWidgets.QMessageBox.Cancel: +# self.datastats.invalidateSpectra() +# self.updateBtn.clicked.connect(self.formatResults) +# self.formatResults() +# else: +# self.updateBtn.clicked.connect(self.formatResults) +# self.formatResults() def importTrueMatchResults(self): self.importWindow = LoadWITecResults(self.datastats, self) self.importWindow.exec() - @QtCore.pyqtSlot(int) - def getAdditivePlot(self, clickedindex): - polymer = self.datastats.typehistogram[clickedindex][0] #get the polymer name, that was clicked on - - if self.datastats.sorted_additives is not None and \ - len(self.datastats.sorted_additives[clickedindex]) > 0: - self.additivePlot = AdditiveViewer(polymer, self.datastats.sorted_additives[clickedindex]) - self.additivePlot.show() +# @QtCore.pyqtSlot(int) +# def getAdditivePlot(self, clickedindex): +# polymer = self.datastats.typehistogram[clickedindex][0] #get the polymer name, that was clicked on +# +# if self.datastats.sorted_additives is not None and \ +# len(self.datastats.sorted_additives[clickedindex]) > 0: +# self.additivePlot = AdditiveViewer(polymer, self.datastats.sorted_additives[clickedindex]) +# self.additivePlot.show() @QtCore.pyqtSlot() - def formatResults(self): - if self.datastats.spectraResults is not None: - print('formatResults') - self.updateBtn.setDisabled(False) - self.optionsGroup.setDisabled(False) - - self.datastats.formatResults(self.hqiSpinBox.value(), self.compHqiSpinBox.value()) + def applyHQIThresholdToResults(self): + self.particleContainer.applyHQITresholdToParticles(self.hqiSpinBox.value()) + self.createHistogramData() + +# def formatResults(self): +# if self.datastats.spectraResults is not None: +# print('formatResults') +# self.updateBtn.setDisabled(False) +# self.optionsGroup.setDisabled(False) +# +# self.datastats.formatResults(self.hqiSpinBox.value(), self.compHqiSpinBox.value()) +# +# if self.datastats.additiveResults is not None: +# self.compHqiSpinBox.setDisabled(False) - if self.datastats.additiveResults is not None: - self.compHqiSpinBox.setDisabled(False) - self.createHistogramData() def createHistogramData(self): - if not self.datastats.createHistogramData(): - QtWidgets.QMessageBox.critical(self, 'Error', 'Inconsistent particle data. Please restore backup!') - return +# if not self.datastats.createHistogramData(): +# QtWidgets.QMessageBox.critical(self, 'Error', 'Inconsistent particle data. Please restore backup!') +# return +# self.particleContainer.updateTypeHistogram() ###Handle Checkboxes for all polymers... self.menuLayout.removeWidget(self.resultScrollarea) @@ -381,7 +379,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): del i self.showTotalSelector.setParent(None) self.showTotalSelector.setDisabled(False) - self.showTotalSelector.stateChanged.connect(self.updateHistogram) + self.showTotalSelector.stateChanged.connect(self.updateHistograms) del self.resultCheckBoxes del self.resultCheckBoxesLayout @@ -391,17 +389,16 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.resultScrollarea = QtWidgets.QScrollArea(self) self.resultScrollarea.setFixedWidth(250) self.resultScrollarea.setWidgetResizable(True) - widget = QtWidgets.QWidget() self.resultScrollarea.setWidget(widget) self.layout_SArea = QtWidgets.QVBoxLayout(widget) - self.resultCheckBoxes = QtWidgets.QGroupBox('Show Polymer Types:') self.resultCheckBoxesLayout = QtWidgets.QVBoxLayout() self.resultCheckBoxesLayout.addWidget(self.showTotalSelector) + #generate new checkboxes self.polymerCheckBoxes = [] - uniquePolymers = self.datastats.getUniquePolymers() + uniquePolymers = self.particleContainer.getUniquePolymers() for index, polymer in enumerate(uniquePolymers): self.polymerCheckBoxes.append(QtWidgets.QCheckBox(self)) self.polymerCheckBoxes[index].setText(polymer) @@ -409,14 +406,12 @@ class ParticleAnalysis(QtWidgets.QMainWindow): if polymer in self.lastSelectedCheckBoxNames: self.polymerCheckBoxes[index].setChecked(True) - self.polymerCheckBoxes[index].stateChanged.connect(self.updateHistogram) + self.polymerCheckBoxes[index].stateChanged.connect(self.updateHistograms) self.polymerCheckBoxes[index].stateChanged.connect(self.createPolymerOverlay) self.resultCheckBoxesLayout.addStretch() self.resultCheckBoxes.setLayout(self.resultCheckBoxesLayout) - self.layout_SArea.addWidget(self.resultCheckBoxes) - self.menuLayout.addWidget(self.resultScrollarea) self.expExcelAct.setDisabled(False) @@ -436,7 +431,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): else: self.displayNewPolymerType() - self.updateHistogram() + self.updateHistograms() self.createPolymerOverlay() def exportToExcel(self): @@ -451,7 +446,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): def updateSpecPlot(self, centerOn=True, highlightContour=True): #draw Sample Spectrum specIndex = self.currentSpectrumIndex - spectra = self.datastats.spectra + spectra = self.particleContainer.spectra particlestats = self.datastats.getParticleStats() self.spec_ax.axis("on") self.spec_ax.clear() @@ -563,33 +558,29 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.currentSpectrumIndex = self.datastats.particles2spectra[self.currentParticleIndex][self.spectrumSelector.value()-1] self.updateSpecPlot() - def updateHistogram(self): + def updateHistograms(self): + self.updateTypeHistogram() + self.updateSizeHistogram() + + + def updateTypeHistogram(self): #draw the general histogram colorList = [] abundancyList = [] labelList = [] - for index, i in enumerate(self.datastats.typehistogram): + typeHistogram = self.particleContainer.getTypeHistogram() + for index, polymType in enumerate(typeHistogram): if not self.selOverlayAct.isChecked() or self.polymerCheckBoxes[index].isChecked(): - abundancyList.append(self.datastats.typehistogram[index][1]) - curColor = self.getColorFromName(self.datastats.typehistogram[index][0]) + abundancyList.append(typeHistogram[polymType]) + curColor = self.getColorFromName(polymType) colorList.append(QtGui.QColor(*curColor)) - if self.datastats.sorted_additives is None: - numads = '' - else: - numads = len(np.unique(self.datastats.sorted_additives[index])) - if numads == 0: - numads = '' - else: - numads = '(' + str(numads) + ')' - numpolymers = i[1] - label = ('{} x ' + self.datastats.typehistogram[index][0] + ' {}').format(numpolymers, numads) - labelList.append(label) - print("abundancyList:", abundancyList) - print("labelList:", labelList) - print("colorList:", colorList) - self.typeHistogram.updateTypes(list(zip(abundancyList, labelList, colorList))) - +# print("abundancyList:", abundancyList) +# print("labelList:", labelList) +# print("colorList:", colorList) + self.typeHistogramPlot.updateTypeHistogram(list(zip(abundancyList, labelList, colorList))) + + def updateSizeHistogram(self): #general size histogram self.sizeHist_ax.clear() self.sizeHist_ax.axis('on') @@ -648,7 +639,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): if ok: self.datastats.colorSeed = text self.datastats.dataset.colorSeed = text - self.updateHistogram() + self.updateHistograms() self.createPolymerOverlay() def getColorFromName(self, name, base255=True): @@ -673,7 +664,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): alpha = (128 if self.transpAct.isChecked() else 255) #get colors for each polymer type - colorList = [QtGui.QColor(255, 255, 255, alpha=50)]*len(self.datastats.particleResults) + colorList = [QtGui.QColor(255, 255, 255, alpha=50)]*len(self.datastats.particleContainer) legendItems = [] for index, indexList in enumerate(self.datastats.indices): diff --git a/analysis/analysiswidgets.py b/analysis/analysiswidgets.py index 16c6c71..d3eeb2d 100755 --- a/analysis/analysiswidgets.py +++ b/analysis/analysiswidgets.py @@ -37,7 +37,7 @@ class ExpExcelDialog(QtWidgets.QDialog): self.datastats = datastats self.particles = self.datastats.getParticleStats() - self.polymers = self.datastats.particleResults + self.polymers = self.datastats.particleContainer self.additives = self.datastats.currentAdditives self.hqis = self.datastats.hqis @@ -262,8 +262,8 @@ class ParticleTypeView(QtWidgets.QScrollArea): self.setAlignment(QtCore.Qt.AlignHCenter) self.widgets = [] - def updateTypes(self, types): - print("Updating polymer type view", flush=True) + def updateTypeHistogram(self, types): +# print("Updating polymer type view", flush=True) for pi in self.widgets: self.indicatorbox.removeWidget(pi) pi.setParent(None) @@ -277,7 +277,7 @@ class ParticleTypeView(QtWidgets.QScrollArea): for index, entry in enumerate(types): num, text, color = entry - print("num, text, color:", num, text, color, flush=True) +# print("num, text, color:", num, text, color, flush=True) pi = ParticleIndicator(num, numtotal, color, text) self.indicatorbox.addWidget(pi) pi.clicked.connect(getIndexFunction(index)) diff --git a/analysis/database.py b/analysis/database.py index 1e909a7..d3cd2a3 100644 --- a/analysis/database.py +++ b/analysis/database.py @@ -35,13 +35,16 @@ from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as Navigatio 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) diff --git a/analysis/datastats.py b/analysis/datastats.py index bc1a5ed..d25bec7 100644 --- a/analysis/datastats.py +++ b/analysis/datastats.py @@ -21,9 +21,186 @@ If not, see . import os import numpy as np import operator -from dataset import loadData, recursiveDictCompare +from PyQt5 import QtWidgets +import importSpectra +try: + from dataset import loadData, recursiveDictCompare + print('exported dataset methods from datastats') +except: + print('failed exported dataset methods from datastats') +class ParticleContainer(object): + def __init__(self, parent): + self.parent = parent + self.particles = [] + self.spectra = None + + self.typeHistogram = None + + def initializeParticles(self, numParticles): + self.particles = [] + for i in range(numParticles): + self.particles.append(Particle(i)) + + def loadSpectraFromDisk(self, fname): + try: + self.spectra = self.tryLoadingNumpySpecFile() + except ImportError: + + fname = QtWidgets.QFileDialog.getOpenFileName(self.parent, 'Select Spectra File', self.dataset.path, 'text file (*.txt)')[0] + + try: + self.spectra, spectraNames = importSpectra.importWITecSpectra(fname) + except ImportError: + try: + self.spectra, spectraNames = importSpectra.importRenishawSpectra(fname) + except ImportError: + self.spectra, spectraNames = importSpectra.importPerkinElmerSpectra(fname) + + if self.spectra is None: + raise ImportError + + def tryLoadingNumpySpecFile(self): + specPath = self.parent.getSpectraFileName() + if os.path.exists(specPath): + return np.load(specPath) + else: + raise ImportError + + def setParticlecontours(self, contours): + assert len(self.particles) == len(contours) + for index, particle in enumerate(self.particles): + particle.contour = contours[index] + + def setParticleStats(self, particlestats): + assert len(self.particles) == len(particlestats) + #particlestats is list of [long, short, longellipse, shortellipse, cv2.contourArea(cnt)] + for index, particle in enumerate(self.particles): + particle.longSize_box = particlestats[0] + particle.shortSize_box = particlestats[1] + particle.longSize_ellipse = particlestats[2] + particle.shortSize_ellipse = particlestats[3] + particle.area = particlestats[4] + + def applyHQITresholdToParticles(self, minHQI): + for particle in self.particles: + particle.applyHQITresholdToMeasurements(minHQI) + + def getNumberOfParticles(self): + return len(self.particles) + + def getMeasurementPixelCoords(self): + coords = [] + for particle in self.particles: + for measurement in particle.measurements: + coords.append([measurement.pixelcoord_x, measurement.pixelcoord_y]) + return coords + + def getListOfParticleAssignments(self): + particleAssignments = [] + for particle in self.particles: + particleAssignments.append(particle.getParticleAssignment()) + return particleAssignments + + def getListOfParticleSizes(self): + particleSizes = [] + + def getTypeHistogram(self): + uniquePolymers = self.getUniquePolymers() + typehistogram = {i: 0 for i in uniquePolymers} + for assignment in self.getListOfParticleAssignments(): + typehistogram[assignment] += 1 + ##sort typehistogram, it will be converted into a list!! + sorted_typehistogram = sorted(typehistogram.items(), key = operator.itemgetter(1), reverse = True) + #convert back to dict + final_typehistogram = {i[0]: i[1] for i in sorted_typehistogram} + return final_typehistogram + + def getUniquePolymers(self): + return np.unique(self.getListOfParticleAssignments()) + + +class Particle(object): + def __init__(self, index): + self.index = index + self.longSize_ellipse = None #TODO: IS CURRENTLY PIXEL SIZE, CONVERT TO MICRONS + self.shortSize_ellipse = None + self.longSize_box = None + self.shortSize_box = None + self.area = None + self.contour = None + self.measurements = [] + + def addEmptyMeasurement(self): + self.measurements.append(Measurement()) + indexOfNewMeasurment = len(self.measurements)-1 + return indexOfNewMeasurment + + def setMeasurementScanIndex(self, indexOfMeasurment, scanIndex): + self.measurements[indexOfMeasurment].ramanScanIndex = scanIndex + + def setMeasurementPixelCoords(self, indexOfMeasurment, x, y): + self.measurements[indexOfMeasurment].pixelcoord_x= x + self.measurements[indexOfMeasurment].pixelcoord_y = y + + def getParticleAssignment(self): + if self.measurementsYieldSameResult(): + return self.measurements[0].getAssignment() + else: + print(f'ERROR: Particle with index {self.index} has non-unique analysis results!') + return None + + def getParticleSize(self): + if self.longSize_ellipse is not None: + return self.longSize_ellipse + elif self.longSize_box is not None: + return self.longSize_box + else: + print(f'Error, particle size requested, but not yet set.\nParticle Index is {self.index}') + raise ValueError + + def measurementsYieldSameResult(self): + allResults = [meas.getAssignment() for meas in self.measurements] + if len(np.unique(allResults)) == 1: + return True + elif len(np.unique(allResults)) > 1: + return False + + def applyHQITresholdToMeasurements(self, minHQI): + for measurement in self.measurements: + measurement.applyHQITrehsold(minHQI) + + +class Measurement(object): + def __init__(self): + self.ramanScanIndex = None + self.pixelcoord_x= None + self.pixelcoord_y = None + + self.assignment_orig = 'Not Evaluated' + self.assignment_afterHQI = None + self.hqi = None + + def setAssignemtAndHQI(self, assignment, hqi): + self.assignment_orig = assignment + self.assignment_afterHQI = 'unknown' + self.hqi = hqi + self.applyHQIThreshold() + + def applyHQIThreshold(self, minHQI=0): + if self.hqi >= minHQI: + self.assignment_afterHQI = self.assignment_orig + else: + self.assignment_afterHQI = 'unknown' + + def getAssignment(self): + if self.assignment_afterHQI is None: + return self.assignment_orig + else: + return self.assignment_afterHQI + + def readDataStats(fname): ds = loadData(fname) datastats = DataStats(ds) @@ -41,7 +218,7 @@ class DataStats(object): self.spectraResults = None #entire List of all spectra assignments self.additiveResults = None #entire List of all additives - self.particleResults = None #final assignment for each particle + self.ParticleContainer = None #final assignment for each particle self.currentPolymers = None #list of polymers after setting entries with low hqi to unknown self.currentAdditives = None #same thing for the additives @@ -76,75 +253,75 @@ class DataStats(object): fname = self.dataset.spectraPath return self.loadSpectra(fname) - def loadSpectra(self, fname): - import time - t0 = time.time() - specfilename = self.dataset.fname.split('.pkl')[0] + '_spectra.npy' - specs = None - if os.path.exists(specfilename): - specs = np.load(specfilename) - else: - try: - specs = np.loadtxt(fname) - #if spectra are already in correct format (WITec, first column: wavenumbers, other columns, intensities), - #we take them, otherwise we have to convert from Renishaw export format... - if not len(np.unique(specs[:, 0])) == len(specs[:, 0]): #--> only unique numbers -> this is the wavenumber column, we have the witec format - #Renishaw Convert - #columns 0 and 1 are x and y coordinates. We dont need them... - startWavenumber = specs[0, 2] - startIndices = np.where(specs[:, 2] == startWavenumber)[0] - - spectra = np.zeros((startIndices[1], len(startIndices)+1)) #create array with shape (numWavenumbers, numSpectra+1) (first column holds wavenumbers) - spectra[:, 0] = specs[startIndices[0]:startIndices[1], 2] - for i in range(len(startIndices)-1): - spectra[:, i+1] = specs[startIndices[i]:startIndices[i+1], 3] - #aaand the last spectrum: - spectra[:, -1] = specs[startIndices[-1]:, 3] - specs = np.flip(spectra, 0) #Renishaw goes from highest to lowest wavenumber, out of whatever reason... - - #write spectra to binary file, that makes reloading them in future significantly faster - np.save(specfilename, specs) - print('loading specs:', time.time()-t0) - self.dataset.spectraPath = fname - except: - pass - self.spectra = specs - return specs - - def loadParticleData(self): - self.particles2spectra = self.dataset.particles2spectra - - sortindices = self.dataset.ramanscansortindex - if self.particles2spectra is None: - print('creating default particles2spectra list') - #no assignment found, so we assume one measurement per particle and use ramanscansortindex for assignment - self.particles2spectra = [[int(np.where(sortindices == i)[0])] for i in range(len(sortindices))] - - #check, if dataset already contains results. Otherwise load them... - return not (self.spectraResults is None or (len(self.spectraResults) != len(sortindices))) +# def loadSpectra(self, fname): +# import time +# t0 = time.time() +# specfilename = self.dataset.fname.split('.pkl')[0] + '_spectra.npy' +# specs = None +# if os.path.exists(specfilename): +# specs = np.load(specfilename) +# else: +# try: +# specs = np.loadtxt(fname) +# #if spectra are already in correct format (WITec, first column: wavenumbers, other columns, intensities), +# #we take them, otherwise we have to convert from Renishaw export format... +# if not len(np.unique(specs[:, 0])) == len(specs[:, 0]): #--> only unique numbers -> this is the wavenumber column, we have the witec format +# #Renishaw Convert +# #columns 0 and 1 are x and y coordinates. We dont need them... +# startWavenumber = specs[0, 2] +# startIndices = np.where(specs[:, 2] == startWavenumber)[0] +# +# spectra = np.zeros((startIndices[1], len(startIndices)+1)) #create array with shape (numWavenumbers, numSpectra+1) (first column holds wavenumbers) +# spectra[:, 0] = specs[startIndices[0]:startIndices[1], 2] +# for i in range(len(startIndices)-1): +# spectra[:, i+1] = specs[startIndices[i]:startIndices[i+1], 3] +# #aaand the last spectrum: +# spectra[:, -1] = specs[startIndices[-1]:, 3] +# specs = np.flip(spectra, 0) #Renishaw goes from highest to lowest wavenumber, out of whatever reason... +# +# #write spectra to binary file, that makes reloading them in future significantly faster +# np.save(specfilename, specs) +# print('loading specs:', time.time()-t0) +# self.dataset.spectraPath = fname +# except: +# pass +# self.spectra = specs +# return specs + +# def loadParticleData(self): +# self.particles2spectra = self.dataset.particles2spectra +# +# sortindices = self.dataset.ramanscansortindex +# if self.particles2spectra is None: +# print('creating default particles2spectra list') +# #no assignment found, so we assume one measurement per particle and use ramanscansortindex for assignment +# self.particles2spectra = [[int(np.where(sortindices == i)[0])] for i in range(len(sortindices))] +# +# #check, if dataset already contains results. Otherwise load them... +# return not (self.spectraResults is None or (len(self.spectraResults) != len(sortindices))) - def invalidateSpectra(self): - self.spectraResults = ['empty']*(self.spectra.shape[1]-1) - self.hqis = [100]*(self.spectra.shape[1]-1) - - def formatResults(self, hqi, compHqi): - if self.spectraResults is not None: - del self.currentPolymers, self.currentAdditives +# def invalidateSpectra(self): +# self.spectraResults = ['empty']*(self.spectra.shape[1]-1) +# self.hqis = [100]*(self.spectra.shape[1]-1) - #convert to arrays (makes indexing easier...) - self.currentPolymers, self.hqis = np.array(self.spectraResults), np.array(self.hqis) - - if self.additiveResults is not None: - self.currentAdditives, self.addhqis = np.array(self.additiveResults), np.array(self.addhqis) - self.compHqiSpinBox.setDisabled(False) - else: - self.currentAdditives = None - - #set poor HQI results to unknown - self.currentPolymers[self.hqis < hqi] = 'unknown' - - if self.currentAdditives is not None: - self.currentAdditives[self.addhqis < compHqi] = 'unknown' +# def formatResults(self, hqi, compHqi): +# if self.spectraResults is not None: +# del self.currentPolymers, self.currentAdditives +# +# #convert to arrays (makes indexing easier...) +# self.currentPolymers, self.hqis = np.array(self.spectraResults), np.array(self.hqis) +# +# if self.additiveResults is not None: +# self.currentAdditives, self.addhqis = np.array(self.additiveResults), np.array(self.addhqis) +# self.compHqiSpinBox.setDisabled(False) +# else: +# self.currentAdditives = None +# +# #set poor HQI results to unknown +# self.currentPolymers[self.hqis < hqi] = 'unknown' +# +# if self.currentAdditives is not None: +# self.currentAdditives[self.addhqis < compHqi] = 'unknown' def getUniquePolymers(self): if self.currentPolymers is None: @@ -159,44 +336,44 @@ class DataStats(object): particlestats[:,4] *= pixelscale #again for the area... return particlestats - def createHistogramData(self): - particlestats = self.getParticleStats() - self.uniquePolymers = np.unique(self.currentPolymers) - self.particleResults = [None]*len(particlestats) - self.typehistogram = {i: 0 for i in self.uniquePolymers} - - if len(self.particles2spectra) != len(particlestats): - return False - - for particleID, specList in enumerate(self.particles2spectra): - assignment = self.currentPolymers[specList[0]] #we take the first result as particle result. Hence, all spectra per particle have to have the same result - self.particleResults[particleID] = assignment - self.typehistogram[assignment] += 1 - - self.particleResults = np.array(self.particleResults) - - ##sort typehistogram, it will be converted into a list!! - self.typehistogram = sorted(self.typehistogram.items(), key = operator.itemgetter(1), reverse = True) - - self.uniquePolymers = [i[0] for i in self.typehistogram] - - self.indices = [] #what particles belong to which polymer type? - for polymer in self.uniquePolymers: - self.indices.append(list(np.where(self.particleResults == polymer)[0])) - - - ###generate additive array for each type in typehistogram: - if self.currentAdditives is None: - self.sorted_additives = None - else: - self.sorted_additives = [] - - for polymer in self.typehistogram: #get additives of each polymer type - self.sorted_additives.append(self.currentAdditives[np.where(self.currentPolymers == polymer[0])]) - for i in range(len(self.sorted_additives)): #sort out 'none' entries - nonentries = np.where(self.sorted_additives[i] == 'none') - self.sorted_additives[i] = np.delete(self.sorted_additives[i], nonentries) - return True +# def createHistogramData(self): +# particlestats = self.getParticleStats() +# self.uniquePolymers = np.unique(self.currentPolymers) +# self.particleResults = [None]*len(particlestats) +# self.typehistogram = {i: 0 for i in self.uniquePolymers} +# +# if len(self.particles2spectra) != len(particlestats): +# return False +# +# for particleID, specList in enumerate(self.particles2spectra): +# assignment = self.currentPolymers[specList[0]] #we take the first result as particle result. Hence, all spectra per particle have to have the same result +# self.particleResults[particleID] = assignment +# self.typehistogram[assignment] += 1 +# +# self.particleResults = np.array(self.particleResults) +# +# ##sort typehistogram, it will be converted into a list!! +# self.typehistogram = sorted(self.typehistogram.items(), key = operator.itemgetter(1), reverse = True) +# +# self.uniquePolymers = [i[0] for i in self.typehistogram] +# +# self.indices = [] #what particles belong to which polymer type? +# for polymer in self.uniquePolymers: +# self.indices.append(list(np.where(self.particleResults == polymer)[0])) +# +# +# ###generate additive array for each type in typehistogram: +# if self.currentAdditives is None: +# self.sorted_additives = None +# else: +# self.sorted_additives = [] +# +# for polymer in self.typehistogram: #get additives of each polymer type +# self.sorted_additives.append(self.currentAdditives[np.where(self.currentPolymers == polymer[0])]) +# for i in range(len(self.sorted_additives)): #sort out 'none' entries +# nonentries = np.where(self.sorted_additives[i] == 'none') +# self.sorted_additives[i] = np.delete(self.sorted_additives[i], nonentries) +# return True def saveAnalysisResults(self, minHQI, compHQI): self.dataset.results = {'polymers': self.spectraResults, diff --git a/analysis/importSpectra.py b/analysis/importSpectra.py new file mode 100644 index 0000000..c9890e4 --- /dev/null +++ b/analysis/importSpectra.py @@ -0,0 +1,68 @@ +#!/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:] diff --git a/analysis/sqlexport.py b/analysis/sqlexport.py index 47ab038..d5936ef 100755 --- a/analysis/sqlexport.py +++ b/analysis/sqlexport.py @@ -20,7 +20,7 @@ class SQLExport(QtWidgets.QDialog): self.setWindowTitle('Export to SQL Database') self.datastats = datastats - self.polymerList = self.datastats.particleResults + self.polymerList = self.datastats.particleContainer particlestats = self.datastats.getParticleStats() self.longSizes = np.round(np.array([i[0] if np.isnan(i[2]) else i[2] for i in particlestats]), 1) self.shortSize = np.round(np.array([i[1] if np.isnan(i[3]) else i[3] for i in particlestats]), 1) diff --git a/dataset.py b/dataset.py index 4cac3e3..175a640 100644 --- a/dataset.py +++ b/dataset.py @@ -24,8 +24,9 @@ import numpy as np import cv2 from helperfunctions import cv2imread_fix, cv2imwrite_fix from copy import copy +from analysis.datastats import ParticleContainer -currentversion = 2 +currentversion = 3 def loadData(fname): retds = None @@ -142,21 +143,22 @@ class DataSet(object): 'compactness': 0.1, 'seedRad': 3} - self.ramanpoints = [] - self.particlecontours = [] - self.particlestats = [] - self.ramanscansortindex = None +# self.ramanpoints = [] +# self.particlecontours = [] +# self.particlestats = [] +# self.ramanscansortindex = None + self.particleContainer = ParticleContainer(self) self.ramanscandone = False - self.results = {'polymers': None, - 'hqis': None, - 'additives': None, - 'additive_hqis': None} +# self.results = {'polymers': None, +# 'hqis': None, +# 'additives': None, +# 'additive_hqis': None} self.resultParams = {'minHQI': None, 'compHQI': None} - self.spectraPath = None - self.particles2spectra = None #links idParticle to corresponding idSpectra (i.e., first measured particle (ID=0) is linked to spectra indices 0 and 1) +# self.spectraPath = None +# self.particles2spectra = None #links idParticle to corresponding idSpectra (i.e., first measured particle (ID=0) is linked to spectra indices 0 and 1) self.colorSeed = 'default' self.resultsUploadedToSQL = [] @@ -231,7 +233,6 @@ class DataSet(object): self.version = 1 - if self.version == 1: print("Converting legacy version 1 to 2") if hasattr(self, 'pixelscale'): @@ -246,9 +247,42 @@ class DataSet(object): del self.imagedim self.version = 2 + + if self.version == 2: + def recreateMeasurement2ParticleFromScanIndices(): + measurements2particles = [[int(np.where(self.ramanscansortindex == i)[0])] for i in range(len(self.ramanscansortindex))] + return measurements2particles + + self.particleContainer.initializeParticles(len(self.particlestats)) + self.particleContainer.setParticlecontours(self.particlecontours) + self.particleContainer.setParticleStats(self.particlestats) + if hasattr(self, 'particles2spectra'): + if self.particles2spectra is not None: + measurements2particles = self.particles2spectra + else: + measurements2particles = recreateMeasurement2ParticleFromScanIndices() + else: + measurements2particles = recreateMeasurement2ParticleFromScanIndices() + + for particleIndex, listOfScanIndices in enumerate(measurements2particles): + curParticle = self.particleContainer.particles[particleIndex] + for measIndex, scanIndex in enumerate(listOfScanIndices): + curParticle.addEmptyMeasurement() + x, y = self.ramanpoints[particleIndex][0], self.ramanpoints[particleIndex][1] + curParticle.setMeasurementPixelCoords(measIndex, x, y) + curParticle.setMeasurementScanIndex(measIndex, scanIndex) + for particle in self.particleContainer.particles: + for meas in particle.measurements: + specIndex = meas.ramanScanIndex + meas.setAssignemtAndHQI(self.results['polymers'][specIndex], self.results['hqis'][specIndex]) + + +# self.version = 3 # add later conversion for higher version numbers here - + + + def getSubImage(self, img, index, draw=True): contour = self.particlecontours[index] x0, x1 = contour[:,0,0].min(), contour[:,0,0].max() @@ -334,7 +368,10 @@ class DataSet(object): def updatePath(self): self.path = os.path.split(self.fname)[0] self.name = os.path.splitext(os.path.basename(self.fname))[0] - + + def getSpectraFileName(self): + return os.path.join(self.path + 'spectra.npy') + def getImageName(self): return os.path.join(self.path, 'fullimage.tif') diff --git a/detectionview.py b/detectionview.py index 923d3a9..20f5c6a 100755 --- a/detectionview.py +++ b/detectionview.py @@ -652,18 +652,31 @@ class ParticleDetectionView(QtWidgets.QWidget): kwargs[name] = valuefunc() seedradius = self.seedradiusedit.value() self.seg.setParameters(**kwargs) - measurementpoints, contours, particlestats = self.seg.apply2Image(self.img, + measurementPoints, contours, particlestats = self.seg.apply2Image(self.img, seedpoints, deletepoints, seedradius) - if measurementpoints is None: # computation was canceled + if measurementPoints is None: # computation was canceled return if self.dataset is not None: self.dataset.ramanscandone = False - self.dataset.ramanpoints = measurementpoints - self.dataset.particlecontours = contours - self.dataset.particlestats = particlestats - self.dataset.ramanscansortindex = [] + numParticles = len(contours) + particleContainer = self.dataset.particleContainer + + particleContainer.initializeParticles(numParticles) + particleContainer.setParticlecontours(contours) + particleContainer.setParticleStats(particlestats) + for particleIndex in measurementPoints: + measPoints = measurementPoints[particleIndex] + for index, point in enumerate(measPoints): + curParticle = particleContainer.particles[point.particleIndex] + curParticle.addEmptyMeasurement() + curParticle.setMeasurementPixelCoords(index, point.x, point.y) + +# self.dataset.ramanpoints = measurementpoints +# self.dataset.particlecontours = contours +# self.dataset.particlestats = particlestats +# self.dataset.ramanscansortindex = [] self.dataset.mode = "prepareraman" self.dataset.save() diff --git a/sample_gepard.cfg b/gepard.cfg similarity index 100% rename from sample_gepard.cfg rename to gepard.cfg diff --git a/gepard.py b/gepard.py index 76d3ac8..f7d3a4f 100755 --- a/gepard.py +++ b/gepard.py @@ -101,12 +101,12 @@ class MeasureParticleWindow(QtWidgets.QMainWindow): fileName = QtWidgets.QFileDialog.getSaveFileName(self, "Create New Project", defaultPath, "*.pkl")[0] if fileName: - if fileName.find(' ') < 0: - self.fname = str(fileName) - self.view.new(self.fname) - self.scalingChanged(1.) - else: - QtWidgets.QMessageBox.critical(self, "Error", "File path must not contain spaces.") +# if fileName.find(' ') < 0: + self.fname = str(fileName) #TODO: No spaces for Renishaw Interface!! + self.view.new(self.fname) + self.scalingChanged(1.) +# else: +# QtWidgets.QMessageBox.critical(self, "Error", "File path must not contain spaces.") @QtCore.pyqtSlot() def about(self): @@ -283,7 +283,6 @@ class MeasureParticleWindow(QtWidgets.QMainWindow): self.menuBar().addMenu(self.toolsMenu) self.menuBar().addMenu(self.helpMenu) - def createToolBar(self): self.toolbar = QtWidgets.QToolBar("Tools") self.toolbar.setIconSize(QtCore.QSize(100,50)) @@ -318,11 +317,10 @@ if __name__ == '__main__': if not os.path.exists(logpath): os.mkdir(logpath) logname = os.path.join(logpath, 'logfile.txt') - - fp = open(logname, "a") - sys.stderr = fp - sys.stdout = fp - +# +# fp = open(logname, "a") +# sys.stderr = fp +# sys.stdout = fp print("starting GEPARD at: " + strftime("%d %b %Y %H:%M:%S", localtime()), flush=True) diff --git a/opticalscan.py b/opticalscan.py index 32f651a..6f185bf 100755 --- a/opticalscan.py +++ b/opticalscan.py @@ -43,7 +43,7 @@ def scan(path, sol, zpositions, grid, controlclass, dataqueue, sys.stderr = fp sys.stdout = fp except IOError: - print('separate loging failed', flush=True) + print('separate logging failed', flush=True) pass print('starting new optical scan', flush=True) diff --git a/ramanscanui.py b/ramanscanui.py index 443ed92..262e469 100644 --- a/ramanscanui.py +++ b/ramanscanui.py @@ -162,9 +162,10 @@ class RamanScanUI(QtWidgets.QWidget): def resetDataset(self, ds): self.dataset = ds - if len(self.dataset.ramanpoints)>0: + numParticles = self.dataset.particleContainer.getNumberOfParticles() + if len(numParticles)>0: self.prun.setEnabled(True) - self.setWindowTitle(str(len(ds.ramanpoints)) + " Particles") + self.setWindowTitle(str(numParticles) + " Particles") @QtCore.pyqtSlot() def stopScan(self): @@ -200,7 +201,7 @@ class RamanScanUI(QtWidgets.QWidget): self.view.imparent.ramanSwitch.hide() self.view.setMicroscopeMode() - points = np.asarray(self.dataset.ramanpoints) + points = np.asarray(self.dataset.particleContainer.getMeasurementPixelCoords()) ramanSettings = {'filename': self.dataset.name, 'numPoints': len(points), 'path': self.dataset.path} @@ -231,7 +232,10 @@ class RamanScanUI(QtWidgets.QWidget): if reply == QtWidgets.QMessageBox.Yes: self.dataset.mode = "ramanscan" - self.dataset.ramanscansortindex = cmin + measurements2particles = [[int(np.where(cmin == i)[0])] for i in range(len(cmin))] + self.dataset.particleContainer.setParticleMeasurementPoints(measurements2particles) + +# self.dataset.ramanscansortindex = cmin self.dataset.saveParticleData() self.view.saveDataSet() self.view.prepareAnalysis() diff --git a/segmentation.py b/segmentation.py index 8d1ca44..ed10111 100644 --- a/segmentation.py +++ b/segmentation.py @@ -41,6 +41,12 @@ class Parameter(object): self.show = show self.linkedParameter = linkedParameter +class MeasurementPoint(object): + def __init__(self, particleIndex, x, y): + self.particleIndex = particleIndex + self.x = x + self.y = y + class Segmentation(object): def __init__(self, dataset=None, parent=None): self.cancelcomputation = False @@ -272,7 +278,7 @@ class Segmentation(object): return long, short, longellipse, shortellipse, cv2.contourArea(cnt) - def measurementPoints(self, binParticle, numPoints=1): + def getMeasurementPoints(self, binParticle, numPoints=1): binParticle = cv2.copyMakeBorder(binParticle, 1, 1, 1, 1, 0) dist = cv2.distanceTransform(np.uint8(binParticle), cv2.DIST_L2,3) ind = np.argmax(dist) @@ -444,12 +450,12 @@ class Segmentation(object): return None, None, None particlestats = [] - measurementpoints = [] + measurementPoints = {} tmpcontours = [contours[i] for i in range(len(contours)) if hierarchy[0,i,3]<0] contours = [] - for i, cnt in enumerate(tmpcontours): + for particleIndex, cnt in enumerate(tmpcontours): label = markers[cnt[0,0,1],cnt[0,0,0]] if label==0: continue @@ -458,10 +464,14 @@ class Segmentation(object): y0, y1 = cnt[:,0,1].min(), cnt[:,0,1].max() subimg = (markers[y0:y1+1,x0:x1+1]).copy() subimg[subimg!=label] = 0 - y, x = self.measurementPoints(subimg) + y, x = self.getMeasurementPoints(subimg) contours.append(cnt) + measurementPoints[particleIndex] = [] for index in range(0, len(x)): - measurementpoints.append([x[index] + x0, y[index] + y0]) + newMeasPoint = MeasurementPoint(particleIndex, x[index] + x0, y[index] + y0) + measurementPoints[particleIndex].append(newMeasPoint) + +# getMeasurementPoints.append([x[index] + x0, y[index] + y0]) print(len(np.unique(markers))-1, len(contours)) print("stats") @@ -472,4 +482,4 @@ class Segmentation(object): tf = time() print("particle detection took:", tf-t0, "seconds") - return measurementpoints, contours, particlestats + return measurementPoints, contours, particlestats diff --git a/viewitems.py b/viewitems.py index 6dc18cc..4a1fa54 100644 --- a/viewitems.py +++ b/viewitems.py @@ -120,10 +120,10 @@ class SegmentationContours(QtWidgets.QGraphicsItem): combineActs = [] assignments = [] for index in self.selectedContours: -# partIndex = int(np.where(self.parent.dataset.ramanscansortindex == index)[0]) partIndex = index - assignments.append(self.parent.analysiswidget.datastats.particleResults[partIndex]) + assignments.append(self.parent.dataset.particleContainer.particles[partIndex].getParticleAssignment()) #TODO: Entangle... assignments.append("other") + for assignment in np.unique(np.array(assignments)): combineActs.append(combineMenu.addAction(assignment)) -- GitLab