diff --git a/analysis/analysisview.py b/analysis/analysisview.py index f5ca7e00bf5a6c397a855f02f3928a5f3846c4eb..2d8df4a072192084c6620d6834a6d926722356b3 100644 --- a/analysis/analysisview.py +++ b/analysis/analysisview.py @@ -399,7 +399,8 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.resultCheckBoxesLayout.addWidget(self.showTotalSelector) #generate new checkboxes self.polymerCheckBoxes = [] - for index, polymer in enumerate(self.datastats.uniquePolymers): + uniquePolymers = self.datastats.getUniquePolymers() + for index, polymer in enumerate(uniquePolymers): self.polymerCheckBoxes.append(QtWidgets.QCheckBox(self)) self.polymerCheckBoxes[index].setText(polymer) self.resultCheckBoxesLayout.addWidget(self.polymerCheckBoxes[index]) @@ -427,7 +428,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.navigationGroup.setEnabled(True) self.polymerComboBox.currentIndexChanged.disconnect() self.polymerComboBox.clear() - self.polymerComboBox.addItems(self.datastats.uniquePolymers) + self.polymerComboBox.addItems(uniquePolymers) self.polymerComboBox.currentIndexChanged.connect(self.displayNewPolymerType) self.polymerIndex = self.polymerComboBox.currentIndex() @@ -489,6 +490,48 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.parent.centerOnRamanIndex(specIndex, centerOn=centerOn, highlightContour=highlightContour) self.parent.highLightRamanIndex(specIndex) self.lastSpectrumInFocus = specIndex + + def selectContour(self, index, centerOn=True): + uniquePolymers = self.datastats.getUniquePolymers() + if uniquePolymers is not None: + #the index is the contour index, find particle index: + specIndex = self.datastats.particles2spectra[index][0] #select first spectrum of partoicle + self.datastats.currentParticleIndex = index + self.datastats.currentSpectrumIndex = specIndex + + selectedPolymer = self.datastats.currentPolymers[specIndex] + try: + self.polymerIndex = uniquePolymers.index(selectedPolymer) + except: + print(selectedPolymer) + raise + + #subparticleIndex + partIndicesOfThatPolymer = self.datastats.indices[self.polymerIndex] + subPartInd = partIndicesOfThatPolymer.index(index) + + #disconnect analysis widgets: + self.particleSelector.valueChanged.disconnect() + self.spectrumSelector.valueChanged.disconnect() + self.polymerComboBox.currentIndexChanged.disconnect() + + #set widgets... + self.particleSelector.setValue(subPartInd+1) + self.particleSelector.setMaximum(len(partIndicesOfThatPolymer)) + + self.spectrumSelector.setValue(1) + self.spectrumSelector.setMaximum(len(self.datastats.particles2spectra[index])) + + selectedPolymer = self.datastats.currentPolymers[specIndex] + self.polymerIndex = uniquePolymers.index(selectedPolymer) + self.polymerComboBox.setCurrentIndex(self.polymerIndex) + + #reconnect all widgets: + self.particleSelector.valueChanged.connect(self.selectParticle) + self.spectrumSelector.valueChanged.connect(self.selectSpectrum) + self.polymerComboBox.currentIndexChanged.connect(self.displayNewPolymerType) + + self.updateSpecPlot(centerOn=centerOn) def displayNewPolymerType(self, resetCurrentIndex=True): self.polymerIndex = self.polymerComboBox.currentIndex() @@ -676,6 +719,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): return color def createPolymerOverlay(self): + uniquePolymers = self.datastats.getUniquePolymers() if not self.noOverlayAct.isChecked() and self.datastats.indices is not None: if len(self.datastats.indices) > 0: @@ -686,9 +730,9 @@ class ParticleAnalysis(QtWidgets.QMainWindow): for index, indexList in enumerate(self.datastats.indices): if self.fullOverlayAct.isChecked() or (self.selOverlayAct.isChecked() and self.polymerCheckBoxes[index].isChecked()): - color = self.getColorFromName(self.datastats.uniquePolymers[index], base255=True) + color = self.getColorFromName(uniquePolymers[index], base255=True) color = QtGui.QColor(color[0], color[1], color[2], alpha=alpha) - legendItems.append((self.datastats.uniquePolymers[index], color)) + legendItems.append((uniquePolymers[index], color)) for i in indexList: colorList[i] = color diff --git a/analysis/datastats.py b/analysis/datastats.py index f2ca564f6fd6f13a1e58af2ef595b36f5b6501a4..31b747b105f4fe01e1631caa5bc78ab2f7cd81b0 100644 --- a/analysis/datastats.py +++ b/analysis/datastats.py @@ -21,6 +21,19 @@ If not, see . import os import numpy as np import operator +from dataset import loadData + + +def readDataStats(fname): + ds = loadData(fname) + datastats = DataStats(ds) + datastats.update() + datastats.loadParticleData() + minHQI = datastats.dataset.resultParams['minHQI'] + compHQI = datastats.dataset.resultParams['compHQI'] + datastats.formatResults(minHQI, compHQI) + datastats.createHistogramData() + return datastats class DataStats(object): def __init__(self, dataset): @@ -34,7 +47,6 @@ class DataStats(object): self.currentPolymers = None #list of polymers after setting entries with low hqi to unknown self.currentAdditives = None #same thing for the additives - self.uniquePolymers = None #list of present polymer types self.spectra = None #acquired spectra self.indices = None #assignment of what spectra-indices belong to what substance @@ -103,7 +115,7 @@ class DataStats(object): def loadParticleData(self): self.particlestats = np.array(self.dataset.particlestats) - pixelscale = (self.dataset.pixelscale_df if self.dataset.imagescanMode == 'df' else self.dataset.pixelscale_bf) + pixelscale = self.dataset.getPixelScale() #convert to mikrometer scale for index in range(len(self.particlestats)): for subindex in range(5): @@ -145,6 +157,11 @@ class DataStats(object): if self.currentAdditives is not None: self.currentAdditives[self.addhqis < compHqi] = 'unknown' + def getUniquePolymers(self): + if self.currentPolymers is None: + return None + return self.uniquePolymers + def createHistogramData(self): self.uniquePolymers = np.unique(self.currentPolymers) self.particleResults = [None]*len(self.particlestats) @@ -192,4 +209,11 @@ class DataStats(object): self.dataset.resultParams = {'minHQI': minHQI, 'compHQI': compHQI} self.dataset.save() - print('saved dataset') \ No newline at end of file + print('saved dataset; Valid:', self.testRead()) + + + def testRead(self): + statsread = readDataStats(self.dataset.fname) + return statsread.__dict__ == self.__dict__ + + \ No newline at end of file diff --git a/dataset.py b/dataset.py index ba4f294ae27ad2c2e0481610c841a9117b8f2ae4..c19f75b9195136fc6129c1b7067fe458ec07fdcb 100644 --- a/dataset.py +++ b/dataset.py @@ -53,6 +53,52 @@ def saveData(dataset, fname): pickle.dump(dataset, fp, protocol=-1) dataset.zvalimg = zvalimg +def arrayCompare(a1, a2): + print("array compare") + ind = np.isnan(a1) + if not np.any(ind): + return np.all(a1==a2) + if a1.shape!=a2.shape: + return False + return np.all(a1[~ind]==a2[~ind]) + +def listCompare(l1, l2): + print("list compare") + if len(l1)!=len(l2): + return False + for l1i, l2i in zip(l1, l2): + if isinstance(l1i, np.ndarray): + if not isinstance(l2i, np.ndarray) or not arrayCompare(l1i, l2i): + return False + elif isinstance(l1i, (list, tuple)): + if not isinstance(l2i, (list, tuple)) or not listCompare(l1i, l2i): + return False + elif l1i!=l2i and ((~np.isnan(l1i)) or (~np.isnan(l2i))): + return False + return True + +def recursiveDictCompare(d1, d2): + for key in d1: + if not key in d2: + return False + a = d1[key] + b = d2[key] + print(key, type(a), type(b)) + if isinstance(a, np.ndarray): + if not isinstance(b, np.ndarray) or not arrayCompare(a, b): + return False + elif isinstance(a, dict): + if not isinstance(b, dict): + return False + if not recursiveDictCompare(a, b): + return False + elif isinstance(a, (list, tuple)): + if not isinstance(b, (list, tuple)) or not listCompare(a, b): + return False + elif a != b: + return False + return True + class DataSet(object): def __init__(self, fname, newProject=False): self.fname = fname @@ -115,6 +161,14 @@ class DataSet(object): self.fname = self.newProject(fname) self.updatePath() + def __eq__(self, other): + return recursiveDictCompare(self.__dict__, other.__dict__) + + def getPixelScale(self, mode=None): + if mode is None: + mode = self.imagescanMode + return (self.pixelscale_df if mode == 'df' else self.pixelscale_bf) + def saveZvalImg(self): if self.zvalimg is not None: cv2imwrite_fix(self.getZvalImageName(), self.zvalimg) @@ -243,8 +297,7 @@ class DataSet(object): p0[1] += self.imagedim_bf[1]/2 return (pixelpos[0]*self.pixelscale_bf + p0[0]), (p0[1] - pixelpos[1]*self.pixelscale_bf) else: - print('mapToRamanMode not understood') - return + raise ValueError(f'mapToLength mode: {mode} not understood') def mapToLengthRaman(self, pixelpos, microscopeMode='df', noz=False): p0x, p0y = self.mapToLength(pixelpos, mode = microscopeMode) @@ -315,9 +368,7 @@ class DataSet(object): saveData(self, self.fname) def saveBackup(self): -# backupNameNotFound = True inc = 0 -# while backupNameNotFound: while True: directory = os.path.dirname(self.fname) filename = self.name + '_backup_' + str(inc) + '.pkl' @@ -327,5 +378,4 @@ class DataSet(object): else: saveData(self, path) return filename -# backupNameNotFound = False diff --git a/sampleview.py b/sampleview.py index c82a0730d9e586f828e09af483cce72932cb225e..dfae213bf99bde60d5ff11fb2c28b79a68b6d17c 100644 --- a/sampleview.py +++ b/sampleview.py @@ -1,578 +1,537 @@ -# -*- coding: utf-8 -*- -""" -GEPARD - Gepard-Enabled PARticle Detection -Copyright (C) 2018 Lars Bittrich and Josef Brandt, Leibniz-Institut für -Polymerforschung Dresden e. V. - -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 . -""" -from PyQt5 import QtCore, QtGui, QtWidgets -import numpy as np -import os -from dataset import DataSet, loadData -from ramancom.ramancontrol import RamanControl, simulatedRaman -from opticalscan import OpticalScan -from ramanscanui import RamanScanUI -from detectionview import ParticleDetectionView -from analysis.analysisview import ParticleAnalysis -from zeissimporter import ZeissImporter -from viewitems import FitPosIndicator, Node, Edge, ScanIndicator, RamanScanIndicator, SegmentationContours -from helperfunctions import polygoncovering, cv2imread_fix -import cv2 -from ramancom.configRaman import RamanConfigWin - -class SampleView(QtWidgets.QGraphicsView): - ScalingChanged = QtCore.pyqtSignal(float) - - def __init__(self, logpath): - super(SampleView, self).__init__() - - self.logpath = logpath - self.item = QtWidgets.QGraphicsPixmapItem() - self.item.setPos(0, 0) - self.item.setAcceptedMouseButtons(QtCore.Qt.NoButton) - self.scaleFactor = 1.0 - scene = QtWidgets.QGraphicsScene(self) - scene.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex) - scene.addItem(self.item) - scene.setBackgroundBrush(QtCore.Qt.darkGray) - self.setScene(scene) - self.setCacheMode(QtWidgets.QGraphicsView.CacheBackground) - self.setViewportUpdateMode(QtWidgets.QGraphicsView.BoundingRectViewportUpdate) - self.setRenderHint(QtGui.QPainter.Antialiasing) - self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) - self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorViewCenter) - self.ramanctrl = RamanControl() - self.simulatedRaman = simulatedRaman - #determine, if ramanSwitch is needed: - self.ramanctrl.connect() - if not self.ramanctrl.connected: - QtWidgets.QMessageBox.warning(self, 'Error', 'Please enable Raman Connection') - return - if self.ramanctrl.getImageDimensions(mode='bf')[0] == self.ramanctrl.getImageDimensions(mode='df')[0]: - self.ramanSwitchNeeded = False - else: - self.ramanSwitchNeeded = True - self.ramanctrl.disconnect() - - self.drag = None - self.mode = None - self.dataset = None - self.fititems = [] - self.boundaryitems = [[],[]] - self.scanitems = [] - self.ramanscanitems = [] - self.imgdata = None - self.isblocked = False - self.contouritem = SegmentationContours(self) - scene.addItem(self.contouritem) - self.detectionwidget = None - self.ramanwidget = RamanScanUI(self.ramanctrl, None, self.logpath, self) - self.ramanwidget.imageUpdate.connect(self.loadPixmap) - self.oscanwidget = OpticalScan(self.ramanctrl, None, self.logpath, self) - self.oscanwidget.imageUpdate.connect(self.loadPixmap) - self.oscanwidget.boundaryUpdate.connect(self.resetBoundary) - self.analysiswidget = None - self.setMinimumSize(600, 600) - self.darkenPixmap = False - self.microscopeMode = None - self.coordTestMode = False - - def takeScreenshot(self): - #TODO: - #LIMIT SCREENSHOT TO ACTUAL VIEWSIZE OF LOADED IMAGE... - #hide scrollbars - self.setHorizontalScrollBarPolicy(1) - self.setVerticalScrollBarPolicy(1) - #capture screen - screen = QtWidgets.QApplication.primaryScreen() - self.repaint() - screenshot = screen.grabWindow(self.winId()) - #unhide scrollbars - self.setHorizontalScrollBarPolicy(0) - self.setVerticalScrollBarPolicy(0) - - fname = self.dataset.path + '/screenshot.png' - validFileName = False - incr = 1 - while not validFileName: - if not os.path.exists(fname): - validFileName = True - else: - fname = self.dataset.path + '/screenshot ({}).png'.format(incr) - incr += 1 - screenshot.save(fname , 'png') - QtWidgets.QMessageBox.about(self, 'Message', 'Saved as {} to project directory.'.format(fname.split('/')[-1])) - - def closeEvent(self, event): - reply = QtWidgets.QMessageBox.question(self, 'Message', - "Are you sure to quit?", QtWidgets.QMessageBox.Yes | - QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No) - - if reply == QtWidgets.QMessageBox.Yes: - self.disconnectRaman() - self.saveDataSet() - event.accept() - self.oscanwidget.close() - if self.detectionwidget is not None: - self.detectionwidget.close() - if self.analysiswidget is not None: - self.analysiswidget.close() - self.ramanwidget.close() - else: - event.ignore() - - def configureRamanControl(self): - self.configWin = RamanConfigWin(self) - self.configWin.show() - - def saveDataSet(self): - if self.dataset is not None: - self.dataset.save() - - @QtCore.pyqtSlot() - def zoomIn(self): - self.scaleImage(1.25) - - @QtCore.pyqtSlot() - def zoomOut(self): - self.scaleImage(0.8) - - @QtCore.pyqtSlot() - def normalSize(self): - self.scaleFactor = 1.0 - self.setTransform(QtGui.QTransform.fromScale(1., 1.)) - self.announceScaling() - - @QtCore.pyqtSlot() - def fitToWindow(self): -# print("fitting to Window") - brect = self.item.sceneBoundingRect() - self.fitInView(0, 0, brect.width(), brect.height(), QtCore.Qt.KeepAspectRatio) - self.scaleFactor = self.transform().m11() - self.announceScaling() - - def switchMode(self, mode, loadnew=False): - if mode is None: - return - assert mode in ["OpticalScan", "ParticleDetection", "RamanScan", "ParticleAnalysis"] - self.oscanwidget.setVisible(False) - if self.detectionwidget is not None: - self.detectionwidget.close() - self.detectionwidget.destroy() - self.ramanwidget.setVisible(False) - self.contouritem.resetContours([]) - self.mode = mode - self.loadPixmap(self.microscopeMode) - if mode == "OpticalScan": - self.oscanwidget.setVisible(True) - self.oscanwidget.resetDataset(self.dataset) - - elif mode == "ParticleDetection": - if self.detectionwidget is None: - self.detectionwidget = ParticleDetectionView(self.imgdata, self.dataset, self) - self.detectionwidget.show() - self.detectionwidget.imageUpdate.connect(self.detectionUpdate) - self.detectionwidget.detectionFinished.connect(self.activateMaxMode) - - elif mode == "RamanScan": - self.ramanwidget.resetDataset(self.dataset) - self.ramanwidget.setVisible(True) - - elif mode == "ParticleAnalysis": - if self.ramanwidget.isVisible(): - self.ramanwidget.setVisible(False) - if self.analysiswidget is None: - print('creating new analysiswidget') - self.analysiswidget = ParticleAnalysis(self.dataset, self) - self.analysiswidget.showMaximized() - else: - print('show maximized already exisiting analysiswidget') - self.analysiswidget.showMaximized() - -# self.ramanwidget.setVisible(False) - if self.detectionwidget is not None: - self.detectionwidget.setVisible(False) - - #show legend: - self.imparent.legend.show() - - if loadnew: - self.fitToWindow() - self.imparent.updateModes(mode, self.getMaxMode()) - - def open(self, fname): - self.saveDataSet() - - #close all widgets - for widget in [self.detectionwidget, self.ramanwidget, self.oscanwidget, self.analysiswidget]: - if widget is not None: - widget.close() - widget.destroy() - del widget - - self.contouritem.resetContours() -# if self.dataset is not None: -# del self.dataset -# self.scene().removeItem(self.contouritem) -# del self.contouritem -# self.contouritem = SegmentationContours(self) -# self.scene().addItem(self.contouritem) - - self.dataset = loadData(fname) - self.setMicroscopeMode() - self.imparent.setWindowTitle(self.dataset.name + (" SIMULATION" if simulatedRaman else "")) - self.imgdata = None - self.activateMaxMode(loadnew=True) - self.imparent.snapshotAct.setEnabled(True) - - def importProject(self, fname): - zimp = ZeissImporter(fname, self.ramanctrl, self) - if zimp.validimport: - zimp.exec() - if zimp.result() == QtWidgets.QDialog.Accepted: - self.open(zimp.gepardname) - - def new(self, fname): - self.saveDataSet() - if self.dataset is not None: - self.dataset.save() - self.dataset = DataSet(fname, newProject=True) - self.setMicroscopeMode() - self.imparent.setWindowTitle(self.dataset.name + (" SIMULATION" if simulatedRaman else "")) - self.imgdata = None - self.activateMaxMode(loadnew=True) - self.imparent.snapshotAct.setEnabled(True) - - def setMicroscopeMode(self): - if self.ramanSwitchNeeded: - self.imparent.ramanSwitch.connectToSampleView() - self.imparent.ramanSwitch.show() - self.microscopeMode = ('df' if self.imparent.ramanSwitch.df_btn.isChecked() else 'bf') - - @QtCore.pyqtSlot() - def activateMaxMode(self, loadnew=False): - mode = self.getMaxMode() - self.imparent.updateModes(self.mode, self.getMaxMode()) - self.switchMode(mode, loadnew=loadnew) - - def blockUI(self): - self.isblocked = True - self.imparent.blockUI() - - def unblockUI(self): - self.isblocked = False - self.imparent.unblockUI(self.ramanctrl.connected) - self.imparent.updateModes(self.mode, self.getMaxMode()) - - def getMaxMode(self): - if self.dataset is None: - return None - if not self.ramanctrl.connected: - self.connectRaman() - if not self.ramanctrl.connected: - return None - maxmode = "OpticalScan" - if os.path.exists(self.dataset.getImageName()): - maxmode = "ParticleDetection" - if len(self.dataset.ramanpoints)>0: - maxmode = "RamanScan" - if self.dataset.ramanscandone: #uncomment!! - maxmode = "ParticleAnalysis" - return maxmode - - def mousePressEvent(self, event): -# if event.button()==QtCore.Qt.RightButton: - if event.button()==QtCore.Qt.MiddleButton: - self.drag = event.pos() - elif event.button()==QtCore.Qt.LeftButton and self.mode in ["OpticalScan", "RamanScan"] \ - and event.modifiers()==QtCore.Qt.ControlModifier: - p0 = self.mapToScene(event.pos()) - if self.dataset is not None and self.dataset.pshift is not None: - if self.dataset.readin: - reply = QtWidgets.QMessageBox.critical(self, 'Dataset is newly read from disk!', - "Coordinate systems might have changed since. Do you want to continue with saved coordinates?", - QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No) - - if reply == QtWidgets.QMessageBox.Yes: - self.dataset.readin = False - else: - return - x, y, z = self.dataset.mapToLengthRaman([p0.x(), p0.y()], - microscopeMode=self.microscopeMode, - noz=(False if self.mode=="RamanScan" else True)) - if z is not None: - assert z>-100. - self.ramanctrl.moveToAbsolutePosition(x, y, z) - elif event.button()==QtCore.Qt.LeftButton and self.mode=="ParticleDetection": - p0 = self.mapToScene(event.pos()) - self.detectionwidget.setImageCenter([p0.x(), p0.y()]) -# elif event.button()==QtCore.Qt.LeftButton and self.mode=="ParticleAnalysis": -# p0 = self.mapToScene(event.pos()) - - else: - p0 = self.mapToScene(event.pos()) - super(SampleView, self).mousePressEvent(event) - - def mouseMoveEvent(self, event): - if self.drag is not None: - p0 = event.pos() - move = self.drag-p0 - self.horizontalScrollBar().setValue(move.x() + self.horizontalScrollBar().value()) - self.verticalScrollBar().setValue(move.y() + self.verticalScrollBar().value()) - - self.drag = p0 - else: - super(SampleView, self).mouseMoveEvent(event) - - def mouseReleaseEvent(self, event): - self.drag = None - super(SampleView, self).mouseReleaseEvent(event) - - def wheelEvent(self, event): - factor = 1.01**(event.angleDelta().y()/8) - self.scaleImage(factor) - - def scaleImage(self, factor): - if factor<1 and not self.imparent.zoomOutAct.isEnabled(): - return - if factor>1 and not self.imparent.zoomInAct.isEnabled(): - return - self.scaleFactor *= factor - self.scale(factor, factor) - self.announceScaling() - - def announceScaling(self): - pixelscale = (self.dataset.pixelscale_df if self.microscopeMode == 'df' else self.dataset.pixelscale_bf) - if self.dataset is None or pixelscale is None: - self.ScalingChanged.emit(-1.0) - else: - self.ScalingChanged.emit(pixelscale/self.scaleFactor) ##CURRENTLY ONLY DARKFIELD!!! FIX NEEDED!!! - - def connectRaman(self): - if not self.ramanctrl.connect(): - msg = QtWidgets.QMessageBox() - msg.setText("Connection failed! Please enable remote control.") - msg.exec() - else: - mode = self.getMaxMode() - self.switchMode(mode) - self.imparent.updateConnected(self.ramanctrl.connected) - - def disconnectRaman(self): - self.ramanctrl.disconnect() - self.imparent.updateConnected(self.ramanctrl.connected) - - @QtCore.pyqtSlot(str) - def detectionUpdate(self): - self.contouritem.resetContours(self.dataset.particlecontours) - self.prepareAnalysis() - self.update() - - @QtCore.pyqtSlot(str) - def loadPixmap(self, microscope_mode='df'): - self.clearItems() - if self.dataset is None: - self.item.setPixmap(QtGui.QPixmap()) - else: - data = self.imgdata - fname = self.dataset.getImageName() - if self.mode == "ParticleDetection" or self.mode == "ParticleAnalysis": - self.contouritem.resetContours(self.dataset.particlecontours) - if data is None and os.path.exists(fname): - data = cv2.cvtColor(cv2imread_fix(fname), cv2.COLOR_BGR2RGB) - self.imgdata = data - if data is not None: - - height, width, channel = data.shape - bytesPerLine = 3 * width - pix = QtGui.QPixmap() - pix.convertFromImage(QtGui.QImage(data.data, - width, height, bytesPerLine, QtGui.QImage.Format_RGB888)) - - self.item.setPixmap(pix) - - if self.darkenPixmap: - self.scene().setBackgroundBrush(QtGui.QColor(5, 5, 5)) - self.item.setOpacity(0.2) - else: - self.scene().setBackgroundBrush(QtCore.Qt.darkGray) - self.item.setOpacity(1) - - - else: - self.item.setPixmap(QtGui.QPixmap()) - if self.mode == "OpticalScan": - for i, p in zip(self.dataset.fitindices, self.dataset.fitpoints): - p = self.dataset.mapToPixel(p, mode=microscope_mode, force=True) - fititem = FitPosIndicator(i+1, pos=p) - self.scene().addItem(fititem) - self.fititems.append(fititem) - if self.mode == "ParticleDetection" or self.mode == "ParticleAnalysis": - self.prepareAnalysis() - else: - self.fitToWindow() - - @QtCore.pyqtSlot() - def resetScanPositions(self): - micMode = ('df' if self.oscanwidget.df_btn.isChecked() else 'bf') - for item in self.scanitems: - self.scene().removeItem(item) - edges, nodes = self.boundaryitems - boundary = [] - for n in nodes: - p = n.pos().x(), n.pos().y() - boundary.append(self.dataset.mapToLength(p, self.microscopeMode, force=True)) - boundary = np.array(boundary) -# print(boundary) - self.dataset.boundary = boundary - if micMode == 'df': - width, height, angle = self.dataset.imagedim_df - else: - width, height, angle = self.dataset.imagedim_bf - - margin = min(width, height)*0.02 - wx, wy = width-margin, height-margin - print(wx,wy) - p1 = polygoncovering(boundary, wx, wy) - b2 = boundary.copy() - b2 = b2[:,[1,0]] - p2 = polygoncovering(b2, wy, wx) - if len(p2) + +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 . +""" +from PyQt5 import QtCore, QtGui, QtWidgets +import numpy as np +import os +from dataset import DataSet, loadData +from ramancom.ramancontrol import RamanControl, simulatedRaman +from opticalscan import OpticalScan +from ramanscanui import RamanScanUI +from detectionview import ParticleDetectionView +from analysis.analysisview import ParticleAnalysis +from zeissimporter import ZeissImporter +from viewitems import FitPosIndicator, Node, Edge, ScanIndicator, RamanScanIndicator, SegmentationContours +from helperfunctions import polygoncovering, cv2imread_fix +import cv2 +from ramancom.configRaman import RamanConfigWin + +class SampleView(QtWidgets.QGraphicsView): + ScalingChanged = QtCore.pyqtSignal(float) + + def __init__(self, logpath): + super(SampleView, self).__init__() + + self.logpath = logpath + self.item = QtWidgets.QGraphicsPixmapItem() + self.item.setPos(0, 0) + self.item.setAcceptedMouseButtons(QtCore.Qt.NoButton) + self.scaleFactor = 1.0 + scene = QtWidgets.QGraphicsScene(self) + scene.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex) + scene.addItem(self.item) + scene.setBackgroundBrush(QtCore.Qt.darkGray) + self.setScene(scene) + self.setCacheMode(QtWidgets.QGraphicsView.CacheBackground) + self.setViewportUpdateMode(QtWidgets.QGraphicsView.BoundingRectViewportUpdate) + self.setRenderHint(QtGui.QPainter.Antialiasing) + self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) + self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorViewCenter) + self.ramanctrl = RamanControl() + self.simulatedRaman = simulatedRaman + #determine, if ramanSwitch is needed: + self.ramanctrl.connect() + if not self.ramanctrl.connected: + QtWidgets.QMessageBox.warning(self, 'Error', 'Please enable Raman Connection') + return + if self.ramanctrl.getImageDimensions(mode='bf')[0] == self.ramanctrl.getImageDimensions(mode='df')[0]: + self.ramanSwitchNeeded = False else: - wxs, wys = width/self.dataset.pixelscale_bf, height/self.dataset.pixelscale_bf - - self.scanitems = [] - for i, p in enumerate(p1): - p = self.dataset.mapToPixel(p, self.microscopeMode, force=True) - s = ScanIndicator(i+1, wxs, wys, p) - self.scene().addItem(s) - self.scanitems.append(s) - - @QtCore.pyqtSlot() - def resetBoundary(self): - micMode = self.microscopeMode - edges, nodes = self.boundaryitems - for item in edges: - self.scene().removeItem(item) - for item in nodes: - self.scene().removeItem(item) - edges, nodes = [], [] - for p in self.dataset.boundary: - p = self.dataset.mapToPixel(p, micMode, force=True) - n = Node(p, self) - nodes.append(n) - self.scene().addItem(n) - for i in range(len(nodes)): - e = Edge(nodes[i-1], nodes[i]) - edges.append(e) - self.scene().addItem(e) - self.boundaryitems = edges, nodes - self.resetScanPositions() - - @QtCore.pyqtSlot(int, bool) - def selectContour(self, index, centerOn=True): - if self.analysiswidget is not None: - if self.analysiswidget.uniquePolymers is not None: - #the index is the contour index, find particle index: - specIndex = self.analysiswidget.particles2spectra[index][0] #select first spectrum of partoicle - self.analysiswidget.currentParticleIndex = index - self.analysiswidget.currentSpectrumIndex = specIndex + self.ramanSwitchNeeded = True + self.ramanctrl.disconnect() + + self.drag = None + self.mode = None + self.dataset = None + self.fititems = [] + self.boundaryitems = [[],[]] + self.scanitems = [] + self.ramanscanitems = [] + self.imgdata = None + self.isblocked = False + self.contouritem = SegmentationContours(self) + scene.addItem(self.contouritem) + self.detectionwidget = None + self.ramanwidget = RamanScanUI(self.ramanctrl, None, self.logpath, self) + self.ramanwidget.imageUpdate.connect(self.loadPixmap) + self.oscanwidget = OpticalScan(self.ramanctrl, None, self.logpath, self) + self.oscanwidget.imageUpdate.connect(self.loadPixmap) + self.oscanwidget.boundaryUpdate.connect(self.resetBoundary) + self.analysiswidget = None + self.setMinimumSize(600, 600) + self.darkenPixmap = False + self.microscopeMode = None + self.coordTestMode = False + + def takeScreenshot(self): + #TODO: + #LIMIT SCREENSHOT TO ACTUAL VIEWSIZE OF LOADED IMAGE... + #hide scrollbars + self.setHorizontalScrollBarPolicy(1) + self.setVerticalScrollBarPolicy(1) + #capture screen + screen = QtWidgets.QApplication.primaryScreen() + self.repaint() + screenshot = screen.grabWindow(self.winId()) + #unhide scrollbars + self.setHorizontalScrollBarPolicy(0) + self.setVerticalScrollBarPolicy(0) + + fname = self.dataset.path + '/screenshot.png' + validFileName = False + incr = 1 + while not validFileName: + if not os.path.exists(fname): + validFileName = True + else: + fname = self.dataset.path + '/screenshot ({}).png'.format(incr) + incr += 1 + screenshot.save(fname , 'png') + QtWidgets.QMessageBox.about(self, 'Message', 'Saved as {} to project directory.'.format(fname.split('/')[-1])) + + def closeEvent(self, event): + reply = QtWidgets.QMessageBox.question(self, 'Message', + "Are you sure to quit?", QtWidgets.QMessageBox.Yes | + QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No) + + if reply == QtWidgets.QMessageBox.Yes: + self.disconnectRaman() + self.saveDataSet() + event.accept() + self.oscanwidget.close() + if self.detectionwidget is not None: + self.detectionwidget.close() + if self.analysiswidget is not None: + self.analysiswidget.close() + self.ramanwidget.close() + else: + event.ignore() + + def configureRamanControl(self): + self.configWin = RamanConfigWin(self) + self.configWin.show() + + def saveDataSet(self): + if self.dataset is not None: + self.dataset.save() + + @QtCore.pyqtSlot() + def zoomIn(self): + self.scaleImage(1.25) + + @QtCore.pyqtSlot() + def zoomOut(self): + self.scaleImage(0.8) + + @QtCore.pyqtSlot() + def normalSize(self): + self.scaleFactor = 1.0 + self.setTransform(QtGui.QTransform.fromScale(1., 1.)) + self.announceScaling() + + @QtCore.pyqtSlot() + def fitToWindow(self): +# print("fitting to Window") + brect = self.item.sceneBoundingRect() + self.fitInView(0, 0, brect.width(), brect.height(), QtCore.Qt.KeepAspectRatio) + self.scaleFactor = self.transform().m11() + self.announceScaling() + + def switchMode(self, mode, loadnew=False): + if mode is None: + return + assert mode in ["OpticalScan", "ParticleDetection", "RamanScan", "ParticleAnalysis"] + self.oscanwidget.setVisible(False) + if self.detectionwidget is not None: + self.detectionwidget.close() + self.detectionwidget.destroy() + self.ramanwidget.setVisible(False) + self.contouritem.resetContours([]) + self.mode = mode + self.loadPixmap(self.microscopeMode) + if mode == "OpticalScan": + self.oscanwidget.setVisible(True) + self.oscanwidget.resetDataset(self.dataset) + + elif mode == "ParticleDetection": + if self.detectionwidget is None: + self.detectionwidget = ParticleDetectionView(self.imgdata, self.dataset, self) + self.detectionwidget.show() + self.detectionwidget.imageUpdate.connect(self.detectionUpdate) + self.detectionwidget.detectionFinished.connect(self.activateMaxMode) + + elif mode == "RamanScan": + self.ramanwidget.resetDataset(self.dataset) + self.ramanwidget.setVisible(True) + + elif mode == "ParticleAnalysis": + if self.ramanwidget.isVisible(): + self.ramanwidget.setVisible(False) + if self.analysiswidget is None: + print('creating new analysiswidget') + self.analysiswidget = ParticleAnalysis(self.dataset, self) + self.analysiswidget.showMaximized() + else: + print('show maximized already exisiting analysiswidget') + self.analysiswidget.showMaximized() + +# self.ramanwidget.setVisible(False) + if self.detectionwidget is not None: + self.detectionwidget.setVisible(False) + + #show legend: + self.imparent.legend.show() + + if loadnew: + self.fitToWindow() + self.imparent.updateModes(mode, self.getMaxMode()) + + def open(self, fname): + self.saveDataSet() + + #close all widgets + for widget in [self.detectionwidget, self.ramanwidget, self.oscanwidget, self.analysiswidget]: + if widget is not None: + widget.close() + widget.destroy() + del widget - selectedPolymer = self.analysiswidget.currentPolymers[specIndex] - try: - self.analysiswidget.polymerIndex = self.analysiswidget.uniquePolymers.index(selectedPolymer) - except: - print(selectedPolymer) - raise + self.contouritem.resetContours() +# if self.dataset is not None: +# del self.dataset +# self.scene().removeItem(self.contouritem) +# del self.contouritem +# self.contouritem = SegmentationContours(self) +# self.scene().addItem(self.contouritem) + + self.dataset = loadData(fname) + self.setMicroscopeMode() + self.imparent.setWindowTitle(self.dataset.name + (" SIMULATION" if simulatedRaman else "")) + self.imgdata = None + self.activateMaxMode(loadnew=True) + self.imparent.snapshotAct.setEnabled(True) + + def importProject(self, fname): + zimp = ZeissImporter(fname, self.ramanctrl, self) + if zimp.validimport: + zimp.exec() + if zimp.result() == QtWidgets.QDialog.Accepted: + self.open(zimp.gepardname) + + def new(self, fname): + self.saveDataSet() + if self.dataset is not None: + self.dataset.save() + self.dataset = DataSet(fname, newProject=True) + self.setMicroscopeMode() + self.imparent.setWindowTitle(self.dataset.name + (" SIMULATION" if simulatedRaman else "")) + self.imgdata = None + self.activateMaxMode(loadnew=True) + self.imparent.snapshotAct.setEnabled(True) + + def setMicroscopeMode(self): + if self.ramanSwitchNeeded: + self.imparent.ramanSwitch.connectToSampleView() + self.imparent.ramanSwitch.show() + self.microscopeMode = ('df' if self.imparent.ramanSwitch.df_btn.isChecked() else 'bf') + + @QtCore.pyqtSlot() + def activateMaxMode(self, loadnew=False): + mode = self.getMaxMode() + self.imparent.updateModes(self.mode, self.getMaxMode()) + self.switchMode(mode, loadnew=loadnew) + + def blockUI(self): + self.isblocked = True + self.imparent.blockUI() + + def unblockUI(self): + self.isblocked = False + self.imparent.unblockUI(self.ramanctrl.connected) + self.imparent.updateModes(self.mode, self.getMaxMode()) + + def getMaxMode(self): + if self.dataset is None: + return None + if not self.ramanctrl.connected: + self.connectRaman() + if not self.ramanctrl.connected: + return None + maxmode = "OpticalScan" + if os.path.exists(self.dataset.getImageName()): + maxmode = "ParticleDetection" + if len(self.dataset.ramanpoints)>0: + maxmode = "RamanScan" + if self.dataset.ramanscandone: #uncomment!! + maxmode = "ParticleAnalysis" + return maxmode + + def mousePressEvent(self, event): +# if event.button()==QtCore.Qt.RightButton: + if event.button()==QtCore.Qt.MiddleButton: + self.drag = event.pos() + elif event.button()==QtCore.Qt.LeftButton and self.mode in ["OpticalScan", "RamanScan"] \ + and event.modifiers()==QtCore.Qt.ControlModifier: + p0 = self.mapToScene(event.pos()) + if self.dataset is not None and self.dataset.pshift is not None: + if self.dataset.readin: + reply = QtWidgets.QMessageBox.critical(self, 'Dataset is newly read from disk!', + "Coordinate systems might have changed since. Do you want to continue with saved coordinates?", + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No) + + if reply == QtWidgets.QMessageBox.Yes: + self.dataset.readin = False + else: + return + x, y, z = self.dataset.mapToLengthRaman([p0.x(), p0.y()], + microscopeMode=self.microscopeMode, + noz=(False if self.mode=="RamanScan" else True)) + if z is not None: + assert z>-100. + self.ramanctrl.moveToAbsolutePosition(x, y, z) + elif event.button()==QtCore.Qt.LeftButton and self.mode=="ParticleDetection": + p0 = self.mapToScene(event.pos()) + self.detectionwidget.setImageCenter([p0.x(), p0.y()]) +# elif event.button()==QtCore.Qt.LeftButton and self.mode=="ParticleAnalysis": +# p0 = self.mapToScene(event.pos()) + + else: + p0 = self.mapToScene(event.pos()) + super(SampleView, self).mousePressEvent(event) + + def mouseMoveEvent(self, event): + if self.drag is not None: + p0 = event.pos() + move = self.drag-p0 + self.horizontalScrollBar().setValue(move.x() + self.horizontalScrollBar().value()) + self.verticalScrollBar().setValue(move.y() + self.verticalScrollBar().value()) + + self.drag = p0 + else: + super(SampleView, self).mouseMoveEvent(event) + + def mouseReleaseEvent(self, event): + self.drag = None + super(SampleView, self).mouseReleaseEvent(event) + + def wheelEvent(self, event): + factor = 1.01**(event.angleDelta().y()/8) + self.scaleImage(factor) + + def scaleImage(self, factor): + if factor<1 and not self.imparent.zoomOutAct.isEnabled(): + return + if factor>1 and not self.imparent.zoomInAct.isEnabled(): + return + self.scaleFactor *= factor + self.scale(factor, factor) + self.announceScaling() + + def announceScaling(self): + pixelscale = self.dataset.getPixelScale(self.microscopeMode) + if self.dataset is None or pixelscale is None: + self.ScalingChanged.emit(-1.0) + else: + self.ScalingChanged.emit(pixelscale/self.scaleFactor) ##CURRENTLY ONLY DARKFIELD!!! FIX NEEDED!!! + + def connectRaman(self): + if not self.ramanctrl.connect(): + msg = QtWidgets.QMessageBox() + msg.setText("Connection failed! Please enable remote control.") + msg.exec() + else: + mode = self.getMaxMode() + self.switchMode(mode) + self.imparent.updateConnected(self.ramanctrl.connected) + + def disconnectRaman(self): + self.ramanctrl.disconnect() + self.imparent.updateConnected(self.ramanctrl.connected) + + @QtCore.pyqtSlot(str) + def detectionUpdate(self): + self.contouritem.resetContours(self.dataset.particlecontours) + self.prepareAnalysis() + self.update() + + @QtCore.pyqtSlot(str) + def loadPixmap(self, microscope_mode='df'): + self.clearItems() + if self.dataset is None: + self.item.setPixmap(QtGui.QPixmap()) + else: + data = self.imgdata + fname = self.dataset.getImageName() + if self.mode == "ParticleDetection" or self.mode == "ParticleAnalysis": + self.contouritem.resetContours(self.dataset.particlecontours) + if data is None and os.path.exists(fname): + data = cv2.cvtColor(cv2imread_fix(fname), cv2.COLOR_BGR2RGB) + self.imgdata = data + if data is not None: - #subparticleIndex - partIndicesOfThatPolymer = self.analysiswidget.indices[self.analysiswidget.polymerIndex] - subPartInd = partIndicesOfThatPolymer.index(index) + height, width, channel = data.shape + bytesPerLine = 3 * width + pix = QtGui.QPixmap() + pix.convertFromImage(QtGui.QImage(data.data, + width, height, bytesPerLine, QtGui.QImage.Format_RGB888)) - #disconnect analysis widgets: - self.analysiswidget.particleSelector.valueChanged.disconnect() - self.analysiswidget.spectrumSelector.valueChanged.disconnect() - self.analysiswidget.polymerComboBox.currentIndexChanged.disconnect() + self.item.setPixmap(pix) - #set widgets... - self.analysiswidget.particleSelector.setValue(subPartInd+1) - self.analysiswidget.particleSelector.setMaximum(len(partIndicesOfThatPolymer)) + if self.darkenPixmap: + self.scene().setBackgroundBrush(QtGui.QColor(5, 5, 5)) + self.item.setOpacity(0.2) + else: + self.scene().setBackgroundBrush(QtCore.Qt.darkGray) + self.item.setOpacity(1) - self.analysiswidget.spectrumSelector.setValue(1) - self.analysiswidget.spectrumSelector.setMaximum(len(self.analysiswidget.particles2spectra[index])) - selectedPolymer = self.analysiswidget.currentPolymers[specIndex] - self.analysiswidget.polymerIndex = self.analysiswidget.uniquePolymers.index(selectedPolymer) - self.analysiswidget.polymerComboBox.setCurrentIndex(self.analysiswidget.polymerIndex) - - #reconnect all widgets: - self.analysiswidget.particleSelector.valueChanged.connect(self.analysiswidget.selectParticle) - self.analysiswidget.spectrumSelector.valueChanged.connect(self.analysiswidget.selectSpectrum) - self.analysiswidget.polymerComboBox.currentIndexChanged.connect(self.analysiswidget.displayNewPolymerType) + else: + self.item.setPixmap(QtGui.QPixmap()) + if self.mode == "OpticalScan": + for i, p in zip(self.dataset.fitindices, self.dataset.fitpoints): + p = self.dataset.mapToPixel(p, mode=microscope_mode, force=True) + fititem = FitPosIndicator(i+1, pos=p) + self.scene().addItem(fititem) + self.fititems.append(fititem) + if self.mode == "ParticleDetection" or self.mode == "ParticleAnalysis": + self.prepareAnalysis() + else: + self.fitToWindow() + + @QtCore.pyqtSlot() + def resetScanPositions(self): + micMode = ('df' if self.oscanwidget.df_btn.isChecked() else 'bf') + for item in self.scanitems: + self.scene().removeItem(item) + edges, nodes = self.boundaryitems + boundary = [] + for n in nodes: + p = n.pos().x(), n.pos().y() + boundary.append(self.dataset.mapToLength(p, self.microscopeMode, force=True)) + boundary = np.array(boundary) +# print(boundary) + self.dataset.boundary = boundary + if micMode == 'df': + width, height, angle = self.dataset.imagedim_df + else: + width, height, angle = self.dataset.imagedim_bf + + margin = min(width, height)*0.02 + wx, wy = width-margin, height-margin + print(wx,wy) + p1 = polygoncovering(boundary, wx, wy) + b2 = boundary.copy() + b2 = b2[:,[1,0]] + p2 = polygoncovering(b2, wy, wx) + if len(p2)0: + data = [] + for i in self.dataset.ramanscansortindex: +# data.append(list(self.dataset.ramanpoints[i])+list(self.dataset.particlestats[i])) + data.append(list(self.dataset.ramanpoints[i])) #particlestats are not needed here. Plus, they dont need to match spectra indices anymore.. + for i in range(len(data)): + item = RamanScanIndicator(self, i+1, 20, (data[i][0],data[i][1])) + self.scene().addItem(item) + self.ramanscanitems.append(item) - self.analysiswidget.updateSpecPlot(centerOn=centerOn) + def highLightRamanIndex(self, index): + if index < len(self.ramanscanitems): + for item in self.ramanscanitems: + item.setHighLight(False) + self.ramanscanitems[index].setHighLight(True) + + def centerOnRamanIndex(self, index, centerOn=True, highlightContour=True): + if centerOn: + self.centerOn(self.ramanscanitems[index]) + +# if highlightContour: +# self.contouritem.selectedContours = [] +# else: +# self.ensureVisible(self.ramanscanitems[index]) + + + def clearItems(self): + for item in self.fititems: + self.scene().removeItem(item) + self.fititems = [] + for item in self.scanitems: + self.scene().removeItem(item) + edges, nodes = self.boundaryitems + for item in edges: + self.scene().removeItem(item) + for item in nodes: + self.scene().removeItem(item) + self.scanitems = [] + self.boundaryitems = [], [] + for item in self.ramanscanitems: + self.scene().removeItem(item) + self.ramanscanitems = [] - - def prepareAnalysis(self): - self.clearItems() - if self.dataset.ramanscansortindex is not None and len(self.dataset.ramanscansortindex)>0: - data = [] - for i in self.dataset.ramanscansortindex: -# data.append(list(self.dataset.ramanpoints[i])+list(self.dataset.particlestats[i])) - data.append(list(self.dataset.ramanpoints[i])) #particlestats are not needed here. Plus, they dont need to match spectra indices anymore.. - for i in range(len(data)): - item = RamanScanIndicator(self, i+1, 20, (data[i][0],data[i][1])) - self.scene().addItem(item) - self.ramanscanitems.append(item) - - def highLightRamanIndex(self, index): - if index < len(self.ramanscanitems): - for item in self.ramanscanitems: - item.setHighLight(False) - self.ramanscanitems[index].setHighLight(True) - - def centerOnRamanIndex(self, index, centerOn=True, highlightContour=True): - if centerOn: - self.centerOn(self.ramanscanitems[index]) - -# if highlightContour: -# self.contouritem.selectedContours = [] -# else: -# self.ensureVisible(self.ramanscanitems[index]) - - - def clearItems(self): - for item in self.fititems: - self.scene().removeItem(item) - self.fititems = [] - for item in self.scanitems: - self.scene().removeItem(item) - edges, nodes = self.boundaryitems - for item in edges: - self.scene().removeItem(item) - for item in nodes: - self.scene().removeItem(item) - self.scanitems = [] - self.boundaryitems = [], [] - for item in self.ramanscanitems: - self.scene().removeItem(item) - self.ramanscanitems = [] - \ No newline at end of file diff --git a/viewitems.py b/viewitems.py index cc9aecbfca8482a7bccf14006e447db1daef15a4..6e709f03b899fe9e33187ea2afb01c3c2c6df223 100644 --- a/viewitems.py +++ b/viewitems.py @@ -22,7 +22,7 @@ import numpy as np from PyQt5 import QtCore, QtWidgets, QtGui class SegmentationContours(QtWidgets.QGraphicsItem): - def __init__(self, parent=None, contours=[], pos=(0,0)): + def __init__(self, parent, contours=[], pos=(0,0)): super().__init__() self.parent = parent self.setPos(pos[0], pos[1]) @@ -122,14 +122,14 @@ class SegmentationContours(QtWidgets.QGraphicsItem): for index in self.selectedContours: # partIndex = int(np.where(self.parent.dataset.ramanscansortindex == index)[0]) partIndex = index - assignments.append(self.parent.analysiswidget.particleResults[partIndex]) + assignments.append(self.analysiswidget.datastats.particleResults[partIndex]) assignments.append("other") for assignment in np.unique(np.array(assignments)): combineActs.append(combineMenu.addAction(assignment)) reassignActs = [] reassignMenu = QtWidgets.QMenu("Reassign particle(s) into") - for polymer in self.parent.analysiswidget.uniquePolymers: + for polymer in self.analysiswidget.datastats.getUniquePolymers(): reassignActs.append(reassignMenu.addAction(polymer)) reassignActs.append(reassignMenu.addAction("other")) @@ -156,7 +156,7 @@ class SegmentationContours(QtWidgets.QGraphicsItem): # QtWidgets.QMessageBox.about(self.parent, "Not yet implemented", "we are getting there...") # return - self.parent.analysiswidget.editor.combineParticles(self.selectedContours, newAssignment) + self.analysiswidget.editor.combineParticles(self.selectedContours, newAssignment) elif action in reassignActs: newAssignment = action.text() @@ -164,7 +164,7 @@ class SegmentationContours(QtWidgets.QGraphicsItem): # QtWidgets.QMessageBox.about(self.parent, "Not yet implemented", "we are getting there...") # return - self.parent.analysiswidget.editor.reassignParticles(self.selectedContours, newAssignment) + self.analysiswidget.editor.reassignParticles(self.selectedContours, newAssignment) class FitPosIndicator(QtWidgets.QGraphicsItem):