diff --git a/analysis/analysisview.py b/analysis/analysisview.py index 9810a2a1ee9d880ef67efb1fb3233e6e6f44ce38..67164a237a18132950ce8a710b4c390fe111de35 100644 --- a/analysis/analysisview.py +++ b/analysis/analysisview.py @@ -113,11 +113,18 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.navigationGroup = QtWidgets.QGroupBox('Navigate through polymers') self.navigationGroup.setDisabled(True) navigationLayout = QtWidgets.QHBoxLayout() + self.specNumberSelector = QtWidgets.QSpinBox() + self.specNumberSelector.setMinimumWidth(150) + self.specNumberSelector.setMinimum(1) + self.specNumberSelector.setMaximum(1E6) + self.jumpToSpecBtn = QtWidgets.QPushButton('Jump To Spectrum of Number:') + self.jumpToSpecBtn.released.connect(self.jumpToSpectrumOfNumber) + self.typeSelectorCombo = QtWidgets.QComboBox() self.typeSelectorCombo.currentIndexChanged.connect(self.displayNewPolymerType) self.typeSelectorCombo.setMinimumWidth(150) self.particleSelector = QtWidgets.QSpinBox() - self.particleSelector.valueChanged.connect(self.updateToSelectedParticle) + self.particleSelector.valueChanged.connect(self.updateSpecPlotToSelectedParticle) self.particleNumberLabel = QtWidgets.QLabel('of xx particles; ') self.spectrumSelector = QtWidgets.QSpinBox() @@ -128,6 +135,8 @@ class ParticleAnalysis(QtWidgets.QMainWindow): spinbox.setSingleStep(1) spinbox.setValue(1) + navigationLayout.addWidget(self.jumpToSpecBtn) + navigationLayout.addWidget(self.specNumberSelector) navigationLayout.addWidget(QtWidgets.QLabel('Select Polymer Type:')) navigationLayout.addWidget(self.typeSelectorCombo) navigationLayout.addStretch() @@ -214,7 +223,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.updateDisplays() self.initializeSpecPlot() self.displayNewPolymerType() - self.updateToSelectedParticle() + self.updateSpecPlotToSelectedParticle() # self.createPolymerOverlay() def createActions(self): @@ -390,16 +399,16 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.createHistogramData() t0 = time.time() self.updateTypeHistogram() - print('update type hist:', round((time.time()-t0)*1000)) + print('update type hist: {} ms'.format(round((time.time()-t0)*1000))) t0 = time.time() self.updateSizeHistogram() - print('update size hist:', round((time.time()-t0)*1000)) + print('update size hist: {} ms'.format(round((time.time()-t0)*1000))) t0 = time.time() self.updateContourColors() - print('update contours:', round((time.time()-t0)*1000)) + print('update contours: {} ms'.format(round((time.time()-t0)*1000))) t0 = time.time() self.updateLegend() - print('update legend:', round((time.time()-t0)*1000)) + print('update legend: {} ms'.format(round((time.time()-t0)*1000))) self.dataset.save() def initializeSpecPlot(self): @@ -474,7 +483,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): def updateContourColors(self): contours = self.parent.contourItems - alpha = (128 if self.transpAct.isChecked() else 255) + alpha = (64 if self.transpAct.isChecked() else 255) selectedPolymers = self.getSelectedPolymers() for particleIndex, contour in enumerate(contours): @@ -501,10 +510,22 @@ class ParticleAnalysis(QtWidgets.QMainWindow): def getSelectedPolymers(self): return [checkbox.text() for checkbox in self.polymerCheckBoxes if checkbox.isChecked()] + + def jumpToSpectrumOfNumber(self): + specIndex = self.specNumberSelector.value()-1 + assert specIndex is not None + partIndex = self.particleContainer.getParticleIndexContainingSpecIndex(specIndex) + assignment = self.particleContainer.getParticleAssignmentByIndex(partIndex) + self.typeSelectorCombo.setCurrentText(assignment) - #TODO: Connect to widget that allows jumping to particular particle - def selectParticleIndex(self, particleIndex, centerOn=True): - self.typeSelectorCombo.currentIndexChanged.disconnect() + partIndices = self.particleContainer.getIndicesOfParticleType(assignment) + self.particleSelector.setValue(partIndices.index(partIndex)+1) + + specIndices = self.particleContainer.getSpectraIndicesOfParticle(partIndex) + self.spectrumSelector.setValue(specIndices.index(specIndex)+1) + + + def selectParticleOfIndex(self, particleIndex, centerOn=True): assignment = self.particleContainer.getParticleAssignmentByIndex(particleIndex) self.typeSelectorCombo.setCurrentText(assignment) self.typeSelectorCombo.currentIndexChanged.connect(self.displayNewPolymerType) @@ -512,9 +533,9 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.particleSelector.valueChanged.disconnect() particleIndices = self.particleContainer.getIndicesOfParticleType(assignment) self.particleSelector.setValue(particleIndices.index(particleIndex)+1) - self.particleSelector.valueChanged.connect(self.updateToSelectedParticle) + self.particleSelector.valueChanged.connect(self.updateSpecPlotToSelectedParticle) - self.updateToSelectedParticle(resetSpectrumCount=True, centerOn=centerOn) + self.updateSpecPlotToSelectedParticle(resetSpectrumCount=True, centerOn=centerOn) def displayNewPolymerType(self, resetCurrentIndex=True): polymerName = self.typeSelectorCombo.currentText() @@ -532,7 +553,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.currentSpectrumIndex = self.getSpectrumIndexFromSpectrumSelector() self.updateSpecPlot(centerOn=False) - def updateToSelectedParticle(self, resetSpectrumCount=True, centerOn=True): + def updateSpecPlotToSelectedParticle(self, resetSpectrumCount=True, centerOn=True): polymerName = self.typeSelectorCombo.currentText() if polymerName != '': self.currentParticleIndex = self.getParticleIndexFromParticleSelector() diff --git a/analysis/particleInfo.py b/analysis/particleInfo.py index 2eacbbc279d0a88bc02e187c7734c370369bd4aa..7e5d09c14f2a961ed743efb168a28941005a2845 100644 --- a/analysis/particleInfo.py +++ b/analysis/particleInfo.py @@ -115,7 +115,12 @@ class ParticleContainer(object): particle = self.particles[index] assert particle.index == index, f'particle.index ({particle.index}) does match requested index in particleList ({index})' return particle - + + def getParticleIndexContainingSpecIndex(self, index): + for particle in self.particles: + if index in particle.getMeasurementIndices(): + return particle.index + def getNumberOfParticles(self): return len(self.particles) diff --git a/analysis/particlePainter.py b/analysis/particlePainter.py index 414a8c947266662668035aa84dd8b418e0b8257a..9a87322ca6662bd60800762dde2929cd3088b7e8 100644 --- a/analysis/particlePainter.py +++ b/analysis/particlePainter.py @@ -21,54 +21,146 @@ If not, see . """ from PyQt5 import QtWidgets, QtCore, QtGui import numpy as np +import cv2 + class ParticlePainter(QtWidgets.QGraphicsItem): - def __init__(self, particleContour, pos=(0,0)): - super().__init__() - self.setZValue(1) - self.setPos(pos[0], pos[1]) - - self.polygon = None - self.particleContour = particleContour + def __init__(self, editorParent, contours, pos=(500,500)): + super(ParticlePainter, self).__init__() + self.editorParent = editorParent + self.viewparent = self.editorParent.viewparent + self.setZValue(5) + self.polygons = None + self.contours = contours self.mousePos = None - self.minRadius = 1 + self.minRadius = 10 self.maxRadius = 500 - self.radius = 20 + self.radius = 50 self.brect = QtCore.QRectF(0,0,1,1) -# self.getBrectAndPolygon() - -# def getBrectAndPolygon(self): -# polygon = QtGui.QPolygonF() -# x0 = self.particleContour[:,0,0].min() -# x1 = self.particleContour[:,0,0].max() -# y0 = self.particleContour[:,0,1].min() -# y1 = self.particleContour[:,0,1].max() -# for point in self.particleContour: -# polygon.append(QtCore.QPointF(point[0,0], point[0,1])) + self.getBrectAndPolygon() + self.painting = False + self.erasing = False -# self.brect.setCoords(x0, y0, x1, y1) -# self.polygon = polygon + def getBrectAndPolygon(self): + polygons = [] + x0 = None + for c in self.contours: + polygon = QtGui.QPolygonF() + if x0 is None: + x0 = c[:,0,0].min() + x1 = c[:,0,0].max() + y0 = c[:,0,1].min() + y1 = c[:,0,1].max() + else: + x0 = min(x0, c[:,0,0].min()) + x1 = max(x1, c[:,0,0].max()) + y0 = min(y0, c[:,0,1].min()) + y1 = max(y1, c[:,0,1].max()) + for ci in c: + polygon.append(QtCore.QPointF(ci[0,0],ci[0,1])) + polygons.append(polygon) + if x0 is None: + self.brect = QtCore.QRectF(0,0,1,1) + else: + self.brect.setCoords(x0,y0,x1,y1) + self.polygons = polygons def boundingRect(self): return self.brect + def mousePressEvent(self, event): + self.mousePos = self.viewparent.mapToScene(event.pos()) + self.erasing = self.painting = False + if event.modifiers()==QtCore.Qt.ControlModifier: + self.painting = True + elif event.modifiers()==QtCore.Qt.ShiftModifier: + self.erasing = True + + if self.painting or self.erasing: + drawPos = self.viewparent.mapToScene(event.pos()) - self.brect.topLeft() + self.drawParticle(drawPos) + def mouseMoveEvent(self, event): - p = event.pos() - self.brect.setCoords(p.x()-self.radius/2, p.y()-self.radius/2, p.x()+self.radius/2, p.y()+self.radius/2) - self.mousePos = p - + self.mousePos = self.viewparent.mapToScene(event.pos()) + self.update() + if self.painting or self.erasing: + drawPos = self.viewparent.mapToScene(event.pos()) - self.brect.topLeft() + self.drawParticle(drawPos) + def wheelEvent(self, event): - if event.angleDelta().y() > 0: - self.radius = np.clip(self.radius+1, self.minRadius, self.maxRadius) + if event.angleDelta().y() < 0: + self.radius = int(np.clip(self.radius+self.radius*0.1, self.minRadius, self.maxRadius)) + else: + self.radius = int(np.clip(self.radius-self.radius*0.1, self.minRadius, self.maxRadius)) + + self.update() + + def mouseReleaseEvent(self, event): + self.erasing = self.painting = False + + def keyPressEvent(self, event): + if event.key() == QtCore.Qt.Key_Escape: + self.editorParent.destroyParticlePainter() + elif event.key() == QtCore.Qt.Key_Return: + self.editorParent.acceptPaintedResult() + + def drawParticle(self, pos): + img, xmin, ymin, padding = self.contoursToImg(self.contours) + center = (int(pos.x()+self.radius), int(pos.y()+self.radius)) + if self.painting: + cv2.circle(img, center, self.radius, 255, -1) + elif self.erasing: + cv2.circle(img, center, self.radius, 0, -1) + + img = np.uint8(img) + self.contours = self.imgToCnt(img, xmin, ymin, padding) + self.getBrectAndPolygon() + self.update() + + def contoursToImg(self, contours): + cnt = np.vstack(tuple(contours)) #combine contous + #draw contours + xmin, xmax = cnt[:,0,:][:, 0].min(), cnt[:,0,:][:, 0].max() + ymin, ymax = cnt[:,0,:][:, 1].min(), cnt[:,0,:][:, 1].max() + padding = self.radius+2 #pixel in each direction + rangex = int(np.round((xmax-xmin)+2*padding)) + rangey = int(np.round((ymax-ymin)+2*padding)) + + img = np.zeros((rangey, rangex), dtype = np.uint8) + for curCnt in contours: + for i in range(len(curCnt)): + curCnt[i][0][0] -= xmin-padding + curCnt[i][0][1] -= ymin-padding + + cv2.drawContours(img, [curCnt], -1, 255, -1) + cv2.drawContours(img, [curCnt], -1, 255, 1) + return img, xmin, ymin, padding + + def imgToCnt(self, img, xmin, ymin, padding): + if cv2.__version__ > '3.5': + contours, hierarchy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE) else: - self.radius = np.clip(self.radius-1, self.minRadius, self.maxRadius) + temp, contours, hierarchy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE) - def paint(self, painter, option, widget): + for contour in contours: + for i in range(len(contour)): + contour[i][0][0] += xmin-padding + contour[i][0][1] += ymin-padding + + return contours + + def paint(self, painter, option, widget): + painter.setPen(QtCore.Qt.white) + painter.drawRect(self.brect) + if self.mousePos is not None: p = [self.mousePos.x(), self.mousePos.y(), self.radius] painter.drawEllipse(p[0]-p[2], p[1]-p[2], 2*p[2], 2*p[2]) -# if self.polygon is not None: -# painter.setPen(QtCore.Qt.white) -# painter.setBrush(QtGui.QColor(200, 200, 200, 128)) -# painter.drawPolygon(self.polygon) \ No newline at end of file + if self.polygons is not None: + for poly in self.polygons: + painter.setBrush(QtGui.QColor(200, 200, 255, 128)) + painter.drawPolygon(poly) + + + \ No newline at end of file diff --git a/analysis/particleeditor.py b/analysis/particleeditor.py index d0b8dc6638f226148e48f90d59aa62d3df77df1e..8a69ff8d54beea2302da3c1b27938b7721d076ef 100644 --- a/analysis/particleeditor.py +++ b/analysis/particleeditor.py @@ -29,9 +29,12 @@ import numpy as np import cv2 from PyQt5 import QtWidgets, QtCore +from analysis.particlePainter import ParticlePainter + class ParticleContextMenu(QtWidgets.QMenu): combineParticlesSignal = QtCore.pyqtSignal(list, str) reassignParticlesSignal = QtCore.pyqtSignal(list, str) + paintParticlesSignal = QtCore.pyqtSignal(list, str) def __init__(self, viewparent): super(ParticleContextMenu, self).__init__() self.viewparent = viewparent @@ -41,18 +44,25 @@ class ParticleContextMenu(QtWidgets.QMenu): def executeAtScreenPos(self, screenPos): self.combineActs = [] self.combineMenu = QtWidgets.QMenu("Combine Particles into") - assignments = [] + + self.paintActs = [] + self.paintMenu = QtWidgets.QMenu("Paint Mode, merge into") + + selctedAssignments = [] for particleIndex in self.selectedParticleIndices: try: assignment = self.particleContainer.getParticleAssignmentByIndex(particleIndex) except: return - assignments.append(assignment) + selctedAssignments.append(assignment) - for assignment in np.unique(assignments): + for assignment in np.unique(selctedAssignments): self.combineActs.append(self.combineMenu.addAction(assignment)) + self.paintActs.append(self.paintMenu.addAction(assignment)) self.combineActs.append(self.combineMenu.addAction("other")) + self.paintActs.append(self.paintMenu.addAction("other")) + self.reassignActs = [] self.reassignMenu = QtWidgets.QMenu("Reassign particle(s) into") @@ -69,15 +79,19 @@ class ParticleContextMenu(QtWidgets.QMenu): self.addMenu(self.combineMenu) self.addMenu(self.reassignMenu) + self.addMenu(self.paintMenu) action = self.exec_(screenPos) - if action in self.combineActs: - newAssignment = self.validifyAssignment(action.text()) - self.combineParticlesSignal.emit(self.selectedParticleIndices, newAssignment) - elif action in self.reassignActs: + if action: newAssignment = self.validifyAssignment(action.text()) - self.reassignParticlesSignal.emit(self.selectedParticleIndices, newAssignment) + + if action in self.combineActs: + self.combineParticlesSignal.emit(self.selectedParticleIndices, newAssignment) + elif action in self.reassignActs: + self.reassignParticlesSignal.emit(self.selectedParticleIndices, newAssignment) + elif action in self.paintActs: + self.paintParticlesSignal.emit(self.selectedParticleIndices, newAssignment) def validifyAssignment(self, assignment): if assignment == "other": @@ -85,7 +99,7 @@ class ParticleContextMenu(QtWidgets.QMenu): return assignment def getNewEntry(self): - text, okClicked = QtWidgets.QInputDialog.getText(QtWidgets.QWidget(), "Custom assignment", "Enter new assignment") + text, okClicked = QtWidgets.QInputDialog.getText(self.viewparent, "Custom assignment", "Enter new assignment") if okClicked and text != '': return text @@ -93,22 +107,26 @@ class ParticleContextMenu(QtWidgets.QMenu): class ParticleEditor(QtCore.QObject): particleContoursChanged = QtCore.pyqtSignal() particleAssignmentChanged = QtCore.pyqtSignal() - def __init__(self, analysisparent, particleContainer): + def __init__(self, viewparent, particleContainer): super(ParticleEditor, self).__init__() self.particleContainer = particleContainer - self.analysisparent = analysisparent #the assigned analysis widget + self.viewparent = viewparent #the assigned analysis widget self.backupFreq = 3 #save a backup every n actions self.neverBackedUp = True self.actionCounter = 0 + + self.storedIndices = [] + self.storedAssignmend = None def connectToSignals(self, contextMenu): contextMenu.combineParticlesSignal.connect(self.combineParticles) contextMenu.reassignParticlesSignal.connect(self.reassignParticles) + contextMenu.paintParticlesSignal.connect(self.paintParticles) def createSafetyBackup(self): self.actionCounter += 1 if self.actionCounter == self.backupFreq-1 or self.neverBackedUp: - backupname = self.analysisparent.dataset.saveBackup() + backupname = self.viewparent.dataset.saveBackup() print('backing up as', backupname) self.neverBackedUp = False self.actionCounter = 0 @@ -122,14 +140,13 @@ class ParticleEditor(QtCore.QObject): stats = self.characterizeParticle(newContour) self.particleContainer.mergeParticles(contourIndices, newContour, stats, newAssignment=newAssignment) - self.particleContoursChanged.emit() -# #save data -# minHQI = self.parent.hqiSpinBox.value() -# compHQI = self.parent.compHqiSpinBox.value() -# if not self.datastats.saveAnalysisResults(minHQI, compHQI): -# QtWidgets.QMessageBox.warning(self.parent, 'Error!', -# 'Data inconsistency after saving!', QtWidgets.QMessageBox.Ok, -# QtWidgets.QMessageBox.Ok) + for ind in contourIndices: + self.viewparent.removeParticleContour(ind) + + self.viewparent.resetContourIndices() + self.viewparent.addParticleContour(newContour, len(self.viewparent.contourItems)) + + #TODO: INCLUDE SANITY CHECK!!!!!!!!! @QtCore.pyqtSlot(list, str) def reassignParticles(self, contourindices, newAssignment): @@ -139,6 +156,41 @@ class ParticleEditor(QtCore.QObject): self.particleContainer.reassignParticleToAssignment(partIndex, newAssignment) self.particleAssignmentChanged.emit() + + @QtCore.pyqtSlot(list, str) + def paintParticles(self, contourIndices, newAssignment): + self.createSafetyBackup + self.storedIndices = contourIndices + self.storedAssignmend = newAssignment + contours = self.particleContainer.getParticleContoursByIndex(contourIndices) + self.particlePainter = ParticlePainter(self, contours) + self.viewparent.normalSize() + self.viewparent.particlePainter = self.particlePainter + self.viewparent.scene().addItem(self.particlePainter) + self.viewparent.update() + + def acceptPaintedResult(self): + newContour = self.mergeContours(self.particlePainter.contours.copy()) + stats = self.characterizeParticle(newContour) + + self.particleContainer.mergeParticles(self.storedIndices, newContour, stats, newAssignment=self.storedAssignmend) + for ind in self.storedIndices: + self.viewparent.removeParticleContour(ind) + + self.viewparent.resetContourIndices() + self.viewparent.addParticleContour(newContour, len(self.viewparent.contourItems)) + + #TODO: INCLUDE SANITY CHECK!!!!!!!!! + self.storedIndices = [] + self.storedAssignmend = None + self.destroyParticlePainter() + + def destroyParticlePainter(self): + if self.particlePainter is not None: + self.viewparent.particlePainter = None + self.viewparent.scene().removeItem(self.particlePainter) + self.viewparent.update() + self.particlePainter = None def mergeContours(self, contours): cnt = np.vstack(tuple(contours)) #combine contous @@ -177,7 +229,6 @@ class ParticleEditor(QtCore.QObject): return newContour - def characterizeParticle(self, contours): ##characterize particle longellipse, shortellipse = np.nan, np.nan diff --git a/sampleview.py b/sampleview.py index 4cfd60b10295791fef9452b5525b2cc719dbea4c..6fc50f52ad2ffba4cb0c928757c47e96f62883fa 100644 --- a/sampleview.py +++ b/sampleview.py @@ -38,8 +38,6 @@ from helperfunctions import polygoncovering, cv2imread_fix from ramancom.configRaman import RamanConfigWin from analysis.particleeditor import ParticleEditor -from analysis.particlePainter import ParticlePainter - class SampleView(QtWidgets.QGraphicsView): ScalingChanged = QtCore.pyqtSignal(float) @@ -62,7 +60,6 @@ class SampleView(QtWidgets.QGraphicsView): self.setRenderHint(QtGui.QPainter.Antialiasing) self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorViewCenter) - self.disableSelection = False self.ramanctrl = RamanControl() self.simulatedRaman = simulatedRaman @@ -89,6 +86,7 @@ class SampleView(QtWidgets.QGraphicsView): self.isblocked = False self.contourItems = [] self.selectedParticleIndices = [] + self.particlePainter = None self.detectionwidget = None self.ramanwidget = RamanScanUI(self.ramanctrl, None, self.logpath, self) @@ -101,8 +99,7 @@ class SampleView(QtWidgets.QGraphicsView): self.darkenPixmap = False self.microscopeMode = None - self.painter = ParticlePainter([]) - self.scene().addItem(self.painter) + self.update() def takeScreenshot(self): @@ -216,7 +213,6 @@ class SampleView(QtWidgets.QGraphicsView): print('show maximized already exisiting analysiswidget') self.analysiswidget.showMaximized() -# self.ramanwidget.setVisible(False) if self.detectionwidget is not None: self.detectionwidget.setVisible(False) @@ -321,40 +317,28 @@ class SampleView(QtWidgets.QGraphicsView): return maxmode def mousePressEvent(self, event): - if not self.disableSelection: - if event.button()==QtCore.Qt.MiddleButton: - self.drag = event.pos() - elif event.button()==QtCore.Qt.LeftButton: + if event.button()==QtCore.Qt.MiddleButton: + self.drag = event.pos() + + elif self.particlePainter is None: + if event.button()==QtCore.Qt.LeftButton: self.checkForContourSelection(event) - event.ignore() - 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)) - x, y, z = self.dataset.mapToLengthRaman([p0.x(), p0.y()], microscopeMode=self.microscopeMode, noz=False) - 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()]) + if self.mode in ["OpticalScan", "RamanScan"] and event.modifiers()==QtCore.Qt.ControlModifier: + p0 = self.mapToScene(event.pos()) + self.moveStageToPosition(p0) + + elif self.mode=="ParticleDetection": + p0 = self.mapToScene(event.pos()) + self.detectionwidget.setImageCenter([p0.x(), p0.y()]) else: p0 = self.mapToScene(event.pos()) super(SampleView, self).mousePressEvent(event) - + + elif self.particlePainter is not None: + self.particlePainter.mousePressEvent(event) + def mouseMoveEvent(self, event): if self.drag is not None: p0 = event.pos() @@ -363,17 +347,50 @@ class SampleView(QtWidgets.QGraphicsView): self.verticalScrollBar().setValue(move.y() + self.verticalScrollBar().value()) self.drag = p0 - else: + elif self.particlePainter is None: + p0 = self.mapToScene(event.pos()) super(SampleView, self).mouseMoveEvent(event) + else: + self.particlePainter.mouseMoveEvent(event) def mouseReleaseEvent(self, event): self.drag = None - super(SampleView, self).mouseReleaseEvent(event) + if self.particlePainter is None: + super(SampleView, self).mouseReleaseEvent(event) + else: + self.particlePainter.mouseReleaseEvent(event) def wheelEvent(self, event): - factor = 1.01**(event.angleDelta().y()/8) - self.scaleImage(factor) - + if self.particlePainter is None: + factor = 1.01**(event.angleDelta().y()/8) + self.scaleImage(factor) + else: + self.particlePainter.wheelEvent(event) + + def keyPressEvent(self, event): + if self.particlePainter is not None: + self.particlePainter.keyPressEvent(event) + + def moveStageToPosition(self, 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)) + noz = (self.mode in ['OpticalScan', 'RamanScan']) + x, y, z = self.dataset.mapToLengthRaman([pos.x(), pos.y()], microscopeMode=self.microscopeMode, noz=noz) + if z is not None: + assert z>-100. + self.ramanctrl.moveToAbsolutePosition(x, y, z) + def checkForContourSelection(self, event): ''' Iam not yet happy how this selection is handled. @@ -398,11 +415,11 @@ class SampleView(QtWidgets.QGraphicsView): if not event.modifiers()==QtCore.Qt.ShiftModifier: addContourToSelection(cnt) - self.analysiswidget.selectParticleIndex(cnt.particleIndex, centerOn=False) + self.analysiswidget.selectParticleOfIndex(cnt.particleIndex, centerOn=False) else: if cnt.particleIndex not in self.selectedParticleIndices: addContourToSelection(cnt) - self.analysiswidget.selectParticleIndex(cnt.particleIndex, centerOn=False) + self.analysiswidget.selectParticleOfIndex(cnt.particleIndex, centerOn=False) elif cnt.particleIndex in self.selectedParticleIndices: removeContourFromSelection(cnt) @@ -562,22 +579,42 @@ class SampleView(QtWidgets.QGraphicsView): self.ramanscanitems.append(item) def resetParticleContours(self): + self.resetBoundary() t0 = time.time() for cnt in self.contourItems: self.scene().removeItem(cnt) self.contourItems = [] if self.dataset is not None: for particleIndex, contour in enumerate(self.dataset.particleContainer.getParticleContours()): - newCnt = SegmentationContour(self, contour) - newCnt.setIndex(particleIndex) - assignment = self.dataset.particleContainer.getParticleAssignmentByIndex(particleIndex) - color = getColorFromNameWithSeed(assignment, self.dataset.colorSeed) - newCnt.setColor(QtGui.QColor(color[0], color[1], color[2], 255)) - self.contourItems.append(newCnt) - self.scene().addItem(newCnt) + self.addParticleContour(contour, particleIndex) +# newCnt = SegmentationContour(self, contour) +# newCnt.setIndex(particleIndex) +# assignment = self.dataset.particleContainer.getParticleAssignmentByIndex(particleIndex) +# color = getColorFromNameWithSeed(assignment, self.dataset.colorSeed) +# newCnt.setColor(QtGui.QColor(color[0], color[1], color[2], 255)) +# self.contourItems.append(newCnt) +# self.scene().addItem(newCnt) self.update() - print('resetted contours:', round((time.time()-t0)*1000)) - + print('resetted contours: {} ms'.format(round((time.time()-t0)*1000))) + + def addParticleContour(self, contour, index): + newCnt = SegmentationContour(self, contour) + newCnt.setIndex(index) + assignment = self.dataset.particleContainer.getParticleAssignmentByIndex(index) + color = getColorFromNameWithSeed(assignment, self.dataset.colorSeed) + newCnt.setColor(QtGui.QColor(color[0], color[1], color[2], 255)) + self.contourItems.append(newCnt) + self.scene().addItem(newCnt) + + def removeParticleContour(self, contourIndex): + correspondingParticle = self.dataset.particleContainer.getParticleOfIndex(contourIndex) #this checks validity of contourIndex + self.scene().removeItem(self.contourItems[contourIndex]) + del self.contourItems[contourIndex] + + def resetContourIndices(self): + for index, contour in enumerate(self.contourItems): + contour.setIndex(index) + def updateLegend(self, legendItems): self.imparent.legend.setTextColorItems(legendItems) diff --git a/viewitems.py b/viewitems.py index 0e1cf145c264c368b2db8af741ead678b3a82a75..8617eb3150e701d31cd7b45ae4d03c24dca72ddb 100644 --- a/viewitems.py +++ b/viewitems.py @@ -29,7 +29,7 @@ class SegmentationContour(QtWidgets.QGraphicsItem): self.setZValue(1) self.setPos(pos[0], pos[1]) self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable) - self.setAcceptedMouseButtons(QtCore.Qt.AllButtons) +# self.setAcceptedMouseButtons(QtCore.Qt.AllButtons) self.brect = QtCore.QRectF(0,0,1,1) self.contourData = contourData @@ -65,7 +65,7 @@ class SegmentationContour(QtWidgets.QGraphicsItem): def setHidden(self, hidden): self.hidden = hidden - def paint(self, painter, option, widget): + def paint(self, painter, option, widget): if self.polygon is not None and not self.hidden: painter.setPen(QtCore.Qt.green) if self.isSelected: @@ -80,6 +80,13 @@ class SegmentationContour(QtWidgets.QGraphicsItem): painter.drawPolygon(self.polygon) +# def mousePressEvent(self, event): +# print('press in contour') +# +# def mouseMoveEvent(self, event): +# print('move in contour') +# + def contextMenuEvent(self, event): if self.isSelected: self.contextMenu = ParticleContextMenu(self.parent)