Commit 514de030 authored by Josef Brandt's avatar Josef Brandt

ViewItems until ParticleDetection

parent 5a00f3f8
......@@ -23,11 +23,11 @@ import logging.handlers
import traceback
import os
from io import StringIO
from PyQt5 import QtCore, QtWidgets, QtGui, QtTest
from PyQt5 import QtCore, QtWidgets, QtGui
from .sampleview import SampleView
from .scalebar import ScaleBar
from .gui.scalebar import ScaleBar
from .ramancom.ramancontrol import defaultPath
from .ramancom.ramanSwitch import RamanSwitch
from .ramancom.lightModeSwitch import LightModeSwitch
from .analysis.colorlegend import ColorLegend
from .gepardlogging import setDefaultLoggingConfig
from .workmodes import ModeHandler
......@@ -39,6 +39,7 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
super(GEPARDMainWindow, self).__init__()
self.setWindowTitle("GEPARD")
self.fname: str = ''
self.resize(900, 700)
self.view = SampleView(logger)
......@@ -46,15 +47,15 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
self.view.ScalingChanged.connect(self.scalingChanged)
self.scalebar = ScaleBar(self)
self.legend = ColorLegend(self)
self.ramanSwitch = RamanSwitch(self)
self.lightModeSwitch = LightModeSwitch(self)
self.view.ScalingChanged.connect(self.scalebar.updateScale)
mdiarea = QtWidgets.QMdiArea(self)
mdiarea.addSubWindow(self.scalebar)
mdiarea.addSubWindow(self.legend)
mdiarea.addSubWindow(self.ramanSwitch)
mdiarea.addSubWindow(self.lightModeSwitch)
self.legend.hide()
self.ramanSwitch.hide()
self.lightModeSwitch.hide()
subview = mdiarea.addSubWindow(self.view)
subview.showMaximized()
......@@ -67,15 +68,18 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
self.createMenus()
self.createToolBar()
self.modeHandler: ModeHandler = ModeHandler(self)
self.modeHandler.modeSwitched.connect(self.view.viewItemHandler.switchToNewMode)
self.updateModes()
def resizeEvent(self, event):
self.scalebar.move(0,self.height()-self.scalebar.height()-30)
self.scalebar.move(0, self.height()-self.scalebar.height()-30)
self.legend.move(self.width()-self.legend.width()-130, 10)
self.ramanSwitch.move(5, 5)
self.lightModeSwitch.move(5, 5)
def closeEvent(self, event):
self.view.closeEvent(event)
def forceCloseAll(self) -> None:
closeAll()
@QtCore.pyqtSlot(float)
......@@ -96,8 +100,7 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
@QtCore.pyqtSlot()
def importProject(self, fileName=False):
if fileName is False:
fileName = QtWidgets.QFileDialog.getOpenFileName(self, "Import Zeiss Zen Project",
defaultPath, "*.xml")[0]
fileName = QtWidgets.QFileDialog.getOpenFileName(self, "Import Zeiss Zen Project", defaultPath, "*.xml")[0]
if fileName:
self.fname = str(fileName)
self.view.importProject(self.fname)
......@@ -106,8 +109,7 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
@QtCore.pyqtSlot()
def new(self, fileName=False):
if fileName is False:
fileName = QtWidgets.QFileDialog.getSaveFileName(self, "Create New Project",
defaultPath, "*.pkl")[0]
fileName = QtWidgets.QFileDialog.getSaveFileName(self, "Create New Project",defaultPath, "*.pkl")[0]
if fileName:
isValid, msg = self.testFilename(fileName)
if isValid:
......@@ -119,7 +121,7 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
@QtCore.pyqtSlot()
def testFilename(self, fileName):
if self.view.ramanctrl.name == 'RenishawCOM': #the renishawCom does not allow Spaces within filePath
if self.view.ramanctrl.name == 'RenishawCOM': # the renishawCom does not allow Spaces within filePath
if fileName.find(' ') == 0:
return False, "File path must not contain spaces."
else:
......@@ -129,20 +131,16 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
@QtCore.pyqtSlot()
def about(self):
QtWidgets.QMessageBox.about(self, 'GEPARD',
"Developed by Complex Fiber Structures GmbH on behalf of Leibniz-IPF Dresden")
QtWidgets.QMessageBox.about(self, 'GEPARD', "Developed by Complex Fiber Structures GmbH "
"on behalf of Leibniz-IPF Dresden")
def createActions(self):
def testDenGebbard(gebbard):
return lambda : testGepard(gebbard)
def runGepardTest(gebbard):
return lambda: testGepard(gebbard)
fname = os.path.join(os.path.split(__file__)[0],
os.path.join('data', 'brand.png'))
self.aboutAct = QtWidgets.QAction(QtGui.QIcon(fname),
"About Particle Measurment", self)
# self.aboutAct.triggered.connect(self.about)
self.aboutAct.triggered.connect(testDenGebbard(self))
fname = os.path.join(os.path.split(__file__)[0], os.path.join('data', 'brand.png'))
self.aboutAct = QtWidgets.QAction(QtGui.QIcon(fname), "About Particle Measurment", self)
self.aboutAct.triggered.connect(self.about)
self.openAct = QtWidgets.QAction("&Open Project...", self)
self.openAct.setShortcut("Ctrl+O")
......@@ -203,15 +201,18 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
self.ramanScanAct.setCheckable(True)
self.ramanScanAct.triggered.connect(QtCore.pyqtSlot()(lambda :self.modeHandler.switchMode("SpectrumScan")))
self.snapshotAct = QtWidgets.QAction("Save Screenshot", self)
self.snapshotAct = QtWidgets.QAction("&Save Screenshot", self)
self.snapshotAct.triggered.connect(self.view.takeScreenshot)
self.snapshotAct.setDisabled(True)
self.configRamanCtrlAct = QtWidgets.QAction("Configure Raman Control", self)
self.configRamanCtrlAct = QtWidgets.QAction("&Configure Raman Control", self)
self.configRamanCtrlAct.triggered.connect(self.view.configureRamanControl)
if self.view.simulatedRaman:
self.configRamanCtrlAct.setDisabled(True)
self.testAct: QtWidgets.QAction = QtWidgets.QAction("&Run Automated Gepard Test")
self.testAct.triggered.connect(runGepardTest(self))
self.noOverlayAct = QtWidgets.QAction("&No Overlay", self)
self.noOverlayAct.setShortcut("1")
self.selOverlayAct = QtWidgets.QAction("&Selected Overlay", self)
......@@ -309,6 +310,7 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
self.toolsMenu = QtWidgets.QMenu("&Tools")
self.toolsMenu.addAction(self.snapshotAct)
self.toolsMenu.addAction(self.configRamanCtrlAct)
self.toolsMenu.addAction(self.testAct)
self.dispMenu = QtWidgets.QMenu("&Display", self)
self.overlayActGroup = QtWidgets.QActionGroup(self.dispMenu)
......
This diff is collapsed.
......@@ -392,7 +392,7 @@ class OpticalScanUI(QtWidgets.QWidget):
areaLayout.addRow(radioGroup)
areaLayout.addRow(label, self.radiusincreaseedit)
areaLayout.addRow(micModeGroup)
if not self.view.ramanSwitchNeeded:
if not self.view.lightModeSwitchNeeded:
micModeGroup.setDisabled(True)
areaLayout.addRow(self.pareaselect)
self.areaOptionsGroup.setLayout(areaLayout)
......@@ -632,8 +632,8 @@ class OpticalScanUI(QtWidgets.QWidget):
if reply != QtWidgets.QMessageBox.Yes:
return
self.view.imparent.ramanSwitch.df_btn.setChecked(self.df_btn.isChecked())
self.view.imparent.ramanSwitch.setDisabled(True)
self.view.imparent.lightModeSwitch.df_btn.setChecked(self.df_btn.isChecked())
self.view.imparent.lightModeSwitch.setDisabled(True)
self.view.setMicroscopeMode()
if self.df_btn.isChecked():
......@@ -733,7 +733,7 @@ class OpticalScanUI(QtWidgets.QWidget):
names = []
for k in range(len(self.dataset.zpositions)):
names.append(os.path.join(self.dataset.getScanPath(), f"image_{i}_{k}.bmp"))
width, height, rotationvalue = (self.dataset.imagedim_df if self.view.imparent.ramanSwitch.df_btn.isChecked() else self.dataset.imagedim_bf)
width, height, rotationvalue = (self.dataset.imagedim_df if self.view.imparent.lightModeSwitch.df_btn.isChecked() else self.dataset.imagedim_bf)
p = self.dataset.grid[i]
p0, p1 = self.dataset.maxdim[:2], self.dataset.maxdim[2:]
......
......@@ -251,7 +251,7 @@ class SpecScanUI(QtWidgets.QWidget):
self.dataset.readin = False
else:
return
self.view.imparent.ramanSwitch.hide()
self.view.imparent.lightModeSwitch.hide()
self.view.setMicroscopeMode()
if not self.ramanctrl.name == 'ThermoFTIRCom':
......
"""
GEPARD - Gepard-Enabled PARticle Detection
Copyright (C) 2018 Lars Bittrich and Josef Brandt, Leibniz-Institut für
Polymerforschung Dresden e. V. <bittrich-lars@ipfdd.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program, see COPYING.
If not, see <https://www.gnu.org/licenses/>.
"""
from PyQt5 import QtCore, QtWidgets
from typing import TYPE_CHECKING, List
from .viewItems.oscanItems import FitPosIndicator, ScanIndicator, Edge, Node
from .viewItems.detectItems import SeedPoint, SegmentationContour
from .viewItems.specscanItems import SpecScanIndicator, ParticleInfo
if TYPE_CHECKING:
from ..sampleview import SampleView
from ..analysis.particleContainer import ParticleContainer
class ViewItemHandler(QtCore.QObject):
def __init__(self, viewParent: 'SampleView'):
super(ViewItemHandler, self).__init__()
self.viewparent: 'SampleView' = viewParent
self.viewparentscene: QtWidgets.QGraphicsScene() = self.viewparent.scene()
self.particleContainer: ParticleContainer = None
self.fititems: List[FitPosIndicator] = []
self.edges: List[Edge] = []
self.nodes: List[Node] = []
self.oscanitems: List[ScanIndicator] = []
self.seedPoints: List[SeedPoint] = []
self.specscanitems: List[SpecScanIndicator] = []
self.contourItems: List[SegmentationContour] = []
self.particleInfoBox: ParticleInfo = None
self.updateFromDataset()
@QtCore.pyqtSlot(str, str)
def switchToNewMode(self, oldMode: str, newMode: str) -> None:
assert oldMode in ['OpticalScan', 'ParticleDetection', 'SpectrumScan', 'None']
assert newMode in ['OpticalScan', 'ParticleDetection', 'SpectrumScan', 'None']
if oldMode == 'OpticalScan':
self._removeItemsFromOpticalScan()
elif oldMode == 'ParticleDetection':
self._removeItemsFromDetection()
elif oldMode == 'SpectrumScan':
self._removeItemsFromSpecScan()
if newMode == 'OpticalScan':
self._addItemsForOpticalScan()
elif newMode == 'ParticleDetection':
self._addItemsForDetection()
elif newMode == 'SpectrumScan':
self._addItemsForSpecScan()
def addParticleInfoBox(self, particleIndex: int):
self.particleInfoBox = ParticleInfo(self.dataset.particleContainer.getParticleOfIndex(particleIndex))
self.scene().addItem(self.particleInfoBox)
def addOptScanItem(self, number, x, y, pos) -> None:
newIndicator: ScanIndicator = ScanIndicator(number, x, y, pos)
self.oscanitems.append(newIndicator)
self.viewparentscene.addItem(newIndicator)
def addEdge(self, node1: Node, node2: Node) -> None:
newEdge: Edge = Edge(node1, node2)
self.edges.append(newEdge)
self.viewparentscene.addItem(newEdge)
def addNode(self, pos) -> None:
newNode: Node = Node(pos, self.viewparent)
self.nodes.append(newNode)
self.viewparentscene.addItem(newNode)
def resetParticleContours(self) -> None:
for item in self.contourItems:
self.viewparentscene.removeItem(item)
self._updateContoursFromDS()
for item in self.contourItems:
self.viewparentscene.addItem(item)
def resetOptScanItems(self) -> None:
for item in self.oscanitems:
self.viewparentscene.removeItem(item)
self.oscanitems = []
def resetOptScanBoundary(self) -> None:
for edge, node in zip(self.edges, self.nodes):
self.viewparentscene.remove(edge)
self.viewparentscene.remove(node)
self.edges, self.nodes = [], []
def updateFromDataset(self) -> None:
if self.viewparent.dataset is not None:
self.particleContainer = self.viewparent.dataset.particleContainer
self._updateSeedpointsFromDS()
self._updateContoursFromDS()
self._updateSpecScanIndicatorsFromDS()
def updateSeedPointsInDisplay(self) -> None:
self._removeItemsFromDetection()
self._updateSeedpointsFromDS()
self._addItemsForDetection()
def removeSeedPointsInDisplay(self) -> None:
self._removeItemsFromDetection()
def _updateSeedpointsFromDS(self) -> None:
self.seedPoints = []
for addPoint in self.viewparent.dataset.seedpoints:
x, y, radius = addPoint
newPoint = SeedPoint(radius, 'add', pos=(x, y))
self.seedPoints.append(newPoint)
for removePoint in self.viewparent.dataset.seeddeletepoints:
x, y, radius = removePoint
newPoint = SeedPoint(radius, 'remove', pos=(x, y))
self.seedPoints.append(newPoint)
def _updateContoursFromDS(self) -> None:
self.contourItems = []
for meas in self.particleContainer.particles:
if meas.ramanScanIndex is not None:
number = meas.ramanScanIndex + 1
item = SpecScanIndicator(self, number, 20, (meas.pixelcoord_x, meas.pixelcoord_y))
self.specscanitems.append(item)
def _updateSpecScanIndicatorsFromDS(self) -> None:
self.specscanitems = []
for meas in self.particleContainer.measurements:
if meas.ramanScanIndex is not None:
number = meas.ramanScanIndex + 1
item = SpecScanIndicator(self, number, 20, (meas.pixelcoord_x, meas.pixelcoord_y))
self.specscanitems.append(item)
def _removeItemsFromOpticalScan(self) -> None:
for item in self._getOptScanItems():
self.viewparentscene.removeItem(item)
def _removeItemsFromDetection(self) -> None:
for item in self.seedPoints:
self.viewparentscene.removeItem(item)
def _removeItemsFromSpecScan(self) -> None:
for item in self.specscanitems:
self.viewparentscene.removeItem(item)
def _addItemsForOpticalScan(self) -> None:
for item in self._getOptScanItems():
self.viewparentscene.addItem(item)
def _addItemsForDetection(self) -> None:
for item in self.seedPoints:
self.viewparentscene.addItem(item)
def _addItemsForSpecScan(self) -> None:
for item in self.specscanitems:
self.viewparentscene.addItem(item)
def _getOptScanItems(self) -> list:
return self.fititems + self.edges + self.nodes + self.oscanitems
# -*- coding: utf-8 -*-
"""
GEPARD - Gepard-Enabled PARticle Detection
Copyright (C) 2018 Lars Bittrich and Josef Brandt, Leibniz-Institut für
Polymerforschung Dresden e. V. <bittrich-lars@ipfdd.de>
Copyright (C) 2018 Lars Bittrich and Josef Brandt, Leibniz-Institut für
Polymerforschung Dresden e. V. <bittrich-lars@ipfdd.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -15,28 +14,51 @@ 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.
along with this program, see COPYING.
If not, see <https://www.gnu.org/licenses/>.
"""
from PyQt5 import QtCore, QtWidgets, QtGui
import numpy as np
from PyQt5 import QtWidgets, QtCore, QtGui
from copy import deepcopy
from .analysis.particleEditor import ParticleContextMenu
from .analysis.particleCharacterization import getParticleCenterPoint, FTIRAperture
from ...analysis.particleEditor import ParticleContextMenu
from ...analysis.particleCharacterization import FTIRAperture
class SeedPoint(QtWidgets.QGraphicsItem):
def __init__(self, radius, seedtype, pos=(0, 0)):
super().__init__()
self.setPos(pos[0], pos[1])
self.seedtype = seedtype
self.radius = radius
def boundingRect(self):
return QtCore.QRectF(-self.radius - 1, -self.radius - 1,
2*self.radius + 2, 2*self.radius + 2)
def paint(self, painter, option, widget):
if self.seedtype == 'add':
painter.setPen(QtCore.Qt.white)
painter.setBrush(QtCore.Qt.white)
elif self.seedtype == 'remove':
painter.setPen(QtCore.Qt.magenta)
painter.setBrush(QtCore.Qt.magenta)
rect = QtCore.QRectF(-self.radius, -self.radius,
2*self.radius, 2*self.radius)
painter.drawEllipse(rect)
class SegmentationContour(QtWidgets.QGraphicsItem):
def __init__(self, viewparent, contourData, pos=(0,0)):
def __init__(self, viewparent, contourData, pos=(0, 0)):
super().__init__()
self.viewparent = viewparent
self.setZValue(1)
self.setPos(pos[0], pos[1])
self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable)
self.brect = QtCore.QRectF(0,0,1,1)
self.brect = QtCore.QRectF(0, 0, 1, 1)
self.contourData = contourData
self.polygon = None
self.hidden = False
self.color = QtGui.QColor(50, 255, 50, 200)
self.particleIndex = None
......@@ -49,29 +71,29 @@ class SegmentationContour(QtWidgets.QGraphicsItem):
:return:
"""
polygon = QtGui.QPolygonF()
x0 = self.contourData[:,0,0].min()
x1 = self.contourData[:,0,0].max()
y0 = self.contourData[:,0,1].min()
y1 = self.contourData[:,0,1].max()
x0 = self.contourData[:, 0, 0].min()
x1 = self.contourData[:, 0, 0].max()
y0 = self.contourData[:, 0, 1].min()
y1 = self.contourData[:, 0, 1].max()
for point in self.contourData:
polygon.append(QtCore.QPointF(point[0,0], point[0,1]))
polygon.append(QtCore.QPointF(point[0, 0], point[0, 1]))
self.brect.setCoords(x0, y0, x1, y1)
self.polygon = polygon
def boundingRect(self):
return self.brect
def setIndex(self, index):
self.particleIndex = index
def setColor(self, color):
self.color = color
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:
painter.setPen(QtCore.Qt.green)
if self.isSelected:
......@@ -80,118 +102,20 @@ class SegmentationContour(QtWidgets.QGraphicsItem):
painter.setBrush(QtGui.QColor(200, 200, 200, alpha))
painter.setPen(QtCore.Qt.white)
else:
painter.setPen(QtGui.QColor(int(self.color.red()*0.7), int(self.color.green()*0.7), int(self.color.blue()*0.7), self.color.alpha()))
painter.setPen(QtGui.QColor(int(self.color.red() * 0.7), int(self.color.green() * 0.7),
int(self.color.blue() * 0.7), self.color.alpha()))
if not self.hidden:
painter.setBrush(self.color)
painter.drawPolygon(self.polygon)
self.viewparent.update()
def contextMenuEvent(self, event):
if self.isSelected:
self.contextMenu = ParticleContextMenu(self.viewparent)
self.viewparent.particleEditor.connectToSignals(self.contextMenu)
self.contextMenu.executeAtScreenPos(event.screenPos())
class FitPosIndicator(QtWidgets.QGraphicsItem):
indicatorSize = 80
def __init__(self, number, pos=(0,0)):
super().__init__()
self.setPos(pos[0], pos[1])
self.number = number
self.setAcceptedMouseButtons(QtCore.Qt.NoButton)
def boundingRect(self):
return QtCore.QRectF(-self.indicatorSize-1,-self.indicatorSize-1,
2*self.indicatorSize+2,2*self.indicatorSize+2)
def paint(self, painter, option, widget):
painter.setPen(QtCore.Qt.green)
painter.setBrush(QtGui.QColor(250,250,0,150))
rect = QtCore.QRectF(-self.indicatorSize,-self.indicatorSize,
2*self.indicatorSize,2*self.indicatorSize)
font = painter.font()
font.setPointSize(40)
painter.setFont(font)
painter.drawText(rect, QtCore.Qt.AlignCenter, str(self.number))
painter.drawEllipse(rect)
def shape(self):
path = QtGui.QPainterPath()
path.addEllipse(self.boundingRect())
return path
class SeedPoint(QtWidgets.QGraphicsItem):
def __init__(self, radius, seedtype, pos=(0,0)):
super().__init__()
self.setPos(pos[0], pos[1])
self.seedtype = seedtype
self.radius = radius
def boundingRect(self):
return QtCore.QRectF(-self.radius-1,-self.radius-1,
2*self.radius+2,2*self.radius+2)
def paint(self, painter, option, widget):
if self.seedtype == 'add':
painter.setPen(QtCore.Qt.white)
painter.setBrush(QtCore.Qt.white)
elif self.seedtype == 'remove':
painter.setPen(QtCore.Qt.magenta)
painter.setBrush(QtCore.Qt.magenta)
rect = QtCore.QRectF(-self.radius,-self.radius,
2*self.radius,2*self.radius)
painter.drawEllipse(rect)
class RamanScanIndicator(QtWidgets.QGraphicsItem):
def __init__(self, view, number, radius, pos=(0,0)):
super().__init__()
self.setAcceptedMouseButtons(QtCore.Qt.NoButton)
self.setZValue(5) #higher zValues will be in foreground. Shall be in foreground!
self.view = view
self.number = number
self.radius = radius
self.highlight = False
self.hidden = False
self.setPos(pos[0], pos[1])
self.hasNoParticleAssigned = False
def setHighLight(self, highlight):
if highlight!=self.highlight:
self.highlight = highlight
self.update()
def boundingRect(self):
return QtCore.QRectF(-self.radius-1,-self.radius-1,
2*self.radius+2,2*self.radius+2)
def shape(self):
path = QtGui.QPainterPath()
path.addEllipse(self.boundingRect())
return path
def paint(self, painter, option, widget):
if not self.hidden:
if self.highlight:
painter.setPen(QtCore.Qt.red)
painter.setBrush(QtGui.QColor(100, 250, 100, 150))
elif self.hasNoParticleAssigned:
painter.setPen(QtCore.Qt.black)
painter.setBrush(QtCore.Qt.red)
else:
painter.setPen(QtCore.Qt.green)
painter.setBrush(QtGui.QColor(50, 50, 250, 150))
rect = QtCore.QRectF(-self.radius, -self.radius, 2*self.radius, 2*self.radius)
painter.drawEllipse(rect)
font = painter.font()
font.setPointSize(10)
painter.setFont(font)
painter.drawText(rect, QtCore.Qt.AlignCenter, str(self.number))
class FTIRApertureIndicator(QtWidgets.QGraphicsItem):
def __init__(self, aperture: FTIRAperture):
......@@ -207,8 +131,8 @@ class FTIRApertureIndicator(QtWidgets.QGraphicsItem):
Calculates the bounding rect (needed for drawing the QGraphicsView) and converts the aperture to a polygon.
:return: