Commit 5033b93c authored by Josef Brandt's avatar Josef Brandt

First Step of Recalculate Coordinate Transfer

Adds an interface for recalculating coordinate system of a dataset. Is found in toolbar of mainWindow: tools->Recalculate Coordinate System
parent 70b1c429
...@@ -203,6 +203,10 @@ class GEPARDMainWindow(QtWidgets.QMainWindow): ...@@ -203,6 +203,10 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
self.configRamanCtrlAct.triggered.connect(self.view.configureRamanControl) self.configRamanCtrlAct.triggered.connect(self.view.configureRamanControl)
if self.view.simulatedRaman: if self.view.simulatedRaman:
self.configRamanCtrlAct.setDisabled(True) self.configRamanCtrlAct.setDisabled(True)
self.recalculateCoordAct = QtWidgets.QAction("&Recalculate Coordinate System")
self.recalculateCoordAct.setDisabled(True)
self.recalculateCoordAct.triggered.connect(self.view.recalculateCoordinateSystem)
self.noOverlayAct = QtWidgets.QAction("&No Overlay", self) self.noOverlayAct = QtWidgets.QAction("&No Overlay", self)
self.noOverlayAct.setShortcut("1") self.noOverlayAct.setShortcut("1")
...@@ -223,18 +227,18 @@ class GEPARDMainWindow(QtWidgets.QMainWindow): ...@@ -223,18 +227,18 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
def updateModes(self, active=None, maxenabled=None): def updateModes(self, active=None, maxenabled=None):
ose, osc, pde, pdc, rse, rsc = [False]*6 ose, osc, pde, pdc, rse, rsc = [False]*6
if maxenabled=="OpticalScan": if maxenabled == "OpticalScan":
ose = True ose = True
elif maxenabled=="ParticleDetection": elif maxenabled == "ParticleDetection":
ose, pde = True, True ose, pde = True, True
elif maxenabled=="RamanScan": elif maxenabled == "RamanScan":
ose, pde, rse = True, True, True ose, pde, rse = True, True, True
if active=="OpticalScan" and ose: if active == "OpticalScan" and ose:
osc = True osc = True
elif active=="ParticleDetection" and pde: elif active == "ParticleDetection" and pde:
pdc = True pdc = True
elif active=="RamanScan" and rse: elif active == "RamanScan" and rse:
rsc = True rsc = True
self.opticalScanAct.setEnabled(ose) self.opticalScanAct.setEnabled(ose)
...@@ -292,6 +296,7 @@ class GEPARDMainWindow(QtWidgets.QMainWindow): ...@@ -292,6 +296,7 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
self.toolsMenu = QtWidgets.QMenu("&Tools") self.toolsMenu = QtWidgets.QMenu("&Tools")
self.toolsMenu.addAction(self.snapshotAct) self.toolsMenu.addAction(self.snapshotAct)
self.toolsMenu.addAction(self.configRamanCtrlAct) self.toolsMenu.addAction(self.configRamanCtrlAct)
self.toolsMenu.addAction(self.recalculateCoordAct)
self.dispMenu = QtWidgets.QMenu("&Display", self) self.dispMenu = QtWidgets.QMenu("&Display", self)
self.overlayActGroup = QtWidgets.QActionGroup(self.dispMenu) self.overlayActGroup = QtWidgets.QActionGroup(self.dispMenu)
......
import numpy as np
from scipy.optimize import least_squares
def getTransform(srcPoints: np.ndarray, dstPoints: np.ndarray, axisInvert: tuple = (False, False, False),
ramanShift: tuple = (0, 0)) -> tuple:
"""
Takes N points from source and target system and uses a least_squared method to find the transformation matrix
:param srcPoints: Nx3 array of xyz-points in source coordinate system
:param dstPoints: Nx3 array of xyz-points in target coordinate system
:param axisInvert: tuple of bools to indicate axis inversion in (x, y, z) dimension
:param ramanShift: x,y tuple of pixel offset of raman laset to image center
:returns resultTuple: transformMatrix, pc - shift, zpc, residuals
"""
points = srcPoints
points[:, 0] -= ramanShift[0]
points[:, 1] -= ramanShift[1]
Parity = np.mat(np.diag([-1. if axisInvert[0] else 1.,
-1. if axisInvert[1] else 1.,
-1. if axisInvert[2] else 1.]))
# zpoints = np.array([m.getPos() for m in self.markers], dtype=np.double)
zpoints = dstPoints
pc = points.mean(axis=0)
zpc = zpoints.mean(axis=0)
points -= pc[np.newaxis, :]
zpoints -= zpc[np.newaxis, :]
def getRotMat(angles):
c1, s1 = np.cos(angles[0]), np.sin(angles[0])
c2, s2 = np.cos(angles[1]), np.sin(angles[1])
c3, s3 = np.cos(angles[2]), np.sin(angles[2])
return np.mat([[c1 * c3 - s1 * c2 * s3, -c1 * s3 - s1 * c2 * c3, s1 * s2],
[s1 * c3 + c1 * c2 * s3, -s1 * s3 + c1 * c2 * c3, -c1 * s2],
[s1 * s3, s2 * c3, c2]])
# find the transformation matrix with best fit for small angles in
# [-45°,45°] for all permutation of markers
# permbest = None
# pointsbest = None
ppoints = points[:, :].copy()
def err(angles_shift):
T = (getRotMat(angles_shift[:3]).T * Parity).A
return (np.dot(zpoints, T) - angles_shift[np.newaxis, 3:] - ppoints).ravel()
angle = np.zeros(3)
opt = least_squares(err, np.concatenate((angle, np.zeros(3))),
bounds=(np.array([-np.pi / 4] * 3 + [-np.inf] * 3),
np.array([np.pi / 4] * 3 + [np.inf] * 3)),
method='dogbox')
permbest = opt
pointsbest = ppoints
optangles = permbest.x[:3]
shift = permbest.x[3:]
T = (getRotMat(optangles).T * Parity).A
error = (np.dot(zpoints, T) - shift[np.newaxis, :] - pointsbest)
# print("Transformation angles:", optangles, flush=True)
# print("Transformation shift:", shift, flush=True)
# print("Transformation err:", error, flush=True)
residuals = np.linalg.norm(error, axis=1)
# accept = True
if np.any(residuals > 1.):
print(f'Transformation residuals are large:{residuals}')
# ret = QtWidgets.QMessageBox.warning(self, 'Warning!',
# f'Transformation residuals are large:{residuals}',
# QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
# QtWidgets.QMessageBox.Ok)
# if ret == QtWidgets.QMessageBox.Cancel:
# accept = False
return T, pc - shift, zpc, residuals
class TrayMarker:
"""
Coordinate Marker on the sample tray. Is NOT in the actual optical image.
"""
index: int = -1
worldCoordX: float = np.nan
worldCoordY: float = np.nan
worldCoordZ: float = np.nan
class ImageMarker:
"""
Coordinate Marker of a characteristic feature within the optical image.
"""
index: int = -1
worldCoordX: float = np.nan
worldCoordY: float = np.nan
worldCoordZ: float = np.nan
imgCoordX: int = -1
imgCoordY: int = -1
...@@ -24,6 +24,7 @@ import numpy as np ...@@ -24,6 +24,7 @@ import numpy as np
import sys import sys
import cv2 import cv2
from copy import copy from copy import copy
from typing import List
from .analysis.particleContainer import ParticleContainer from .analysis.particleContainer import ParticleContainer
from .legacyConvert import legacyConversion, currentVersion from .legacyConvert import legacyConversion, currentVersion
from .helperfunctions import cv2imwrite_fix, cv2imread_fix from .helperfunctions import cv2imwrite_fix, cv2imread_fix
...@@ -31,9 +32,11 @@ from .helperfunctions import cv2imwrite_fix, cv2imread_fix ...@@ -31,9 +32,11 @@ from .helperfunctions import cv2imwrite_fix, cv2imread_fix
# (no relative import) # (no relative import)
from . import dataset from . import dataset
from . import analysis from . import analysis
from .coordinatetransform import TrayMarker, ImageMarker
sys.modules['dataset'] = dataset sys.modules['dataset'] = dataset
sys.modules['analysis'] = analysis sys.modules['analysis'] = analysis
def loadData(fname): def loadData(fname):
retds = None retds = None
with open(fname, "rb") as fp: with open(fname, "rb") as fp:
...@@ -120,11 +123,11 @@ class DataSet(object): ...@@ -120,11 +123,11 @@ class DataSet(object):
self.version = currentVersion self.version = currentVersion
self.lastpos = None self.lastpos = None
self.maxdim = None self.maxdim = None
self.pixelscale_df = None # µm / pixel --> scale of DARK FIELD camera (used for image stitching) self.pixelscale_df = None # µm / pixel --> scale of DARK FIELD camera (used for image stitching)
self.pixelscale_bf = None # µm / pixel of DARK FIELD camera (set to same as bright field, if both use the same camera) self.pixelscale_bf = None # µm / pixel of DARK FIELD camera (set to same as bright field, if both use the same camera)
self.imagedim_bf = None # width, height, angle of BRIGHT FIELD camera self.imagedim_bf = None # width, height, angle of BRIGHT FIELD camera
self.imagedim_df = None # width, height, angle of DARK FIELD camera (set to same as bright field, if both use the same camera) self.imagedim_df = None # width, height, angle of DARK FIELD camera (set to same as bright field, if both use the same camera)
self.imagescanMode = 'df' #was the fullimage acquired in dark- or brightfield? self.imagescanMode = 'df' # was the fullimage acquired in dark- or brightfield?
self.fitpoints = [] # manually adjusted positions aquired to define the specimen geometry self.fitpoints = [] # manually adjusted positions aquired to define the specimen geometry
self.fitindices = [] # which of the five positions in the ui are already known self.fitindices = [] # which of the five positions in the ui are already known
self.boundary = [] # scan boundary computed by a circle around the fitpoints + manual adjustments self.boundary = [] # scan boundary computed by a circle around the fitpoints + manual adjustments
...@@ -132,7 +135,9 @@ class DataSet(object): ...@@ -132,7 +135,9 @@ class DataSet(object):
self.zpositions = [] # z-positions for optical scan self.zpositions = [] # z-positions for optical scan
self.heightmap = None self.heightmap = None
self.zvalimg = None self.zvalimg = None
self.coordinatetransform = None # if imported form extern source coordinate system may be rotated self.coordinatetransform = None # if imported form extern source coordinate system may be rotated
self.trayMarkers: List[TrayMarker] = [] # list of markers on the sample tray
self.imageMarkers: List[ImageMarker] = [] # list of coordinate markers within the image
self.signx = 1. self.signx = 1.
self.signy = -1. self.signy = -1.
...@@ -141,7 +146,6 @@ class DataSet(object): ...@@ -141,7 +146,6 @@ class DataSet(object):
# parameters specifically for raman scan # parameters specifically for raman scan
self.pshift = None # shift of raman scan position relative to image center self.pshift = None # shift of raman scan position relative to image center
self.coordOffset = [0, 0] #offset of entire coordinate system
self.seedpoints = np.array([]) self.seedpoints = np.array([])
self.seeddeletepoints = np.array([]) self.seeddeletepoints = np.array([])
self.detectParams = {'points': np.array([[50,0],[100,200],[200,255]]), self.detectParams = {'points': np.array([[50,0],[100,200],[200,255]]),
...@@ -242,8 +246,6 @@ class DataSet(object): ...@@ -242,8 +246,6 @@ class DataSet(object):
if not force: if not force:
assert not self.readin assert not self.readin
p0 = copy(self.lastpos) p0 = copy(self.lastpos)
p0[0] += self.coordOffset[0]
p0[1] += self.coordOffset[1]
if mode == 'df': if mode == 'df':
p0[0] -= self.signx*self.imagedim_df[0]/2 p0[0] -= self.signx*self.imagedim_df[0]/2
p0[1] -= self.signy*self.imagedim_df[1]/2 p0[1] -= self.signy*self.imagedim_df[1]/2
...@@ -262,7 +264,7 @@ class DataSet(object): ...@@ -262,7 +264,7 @@ class DataSet(object):
if self.coordinatetransform is not None: if self.coordinatetransform is not None:
T, pc = self.coordinatetransform T, pc = self.coordinatetransform
x, y, z = (np.dot(np.array([x,y,z]), T) + pc) x, y, z = (np.dot(np.array([x, y, z]), T) + pc)
if returnz: if returnz:
return x, y, z return x, y, z
......
from PyQt5 import QtWidgets, QtGui, QtCore
import numpy as np
from typing import List
from copy import deepcopy
from ..coordinatetransform import ImageMarker, TrayMarker, getTransform
from ..ramancom.ramanbase import RamanBase
class CoordTransformUI(QtWidgets.QWidget):
def __init__(self, viewParent):
super(CoordTransformUI, self).__init__()
self.setWindowTitle('Recalculate Coordinate System')
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.viewParent = viewParent
self.ramanctrl: RamanBase = self.viewParent.ramanctrl
self.imageMarkers: List[ImageMarker] = [] # in the new coord system
self.newImageMarkers: List[ImageMarker] = []
self.imageMarkerWidgets: List[CoordinateSystemMarker] = []
self.trayMarkers: List[TrayMarker] = [] # in the new coord system
self.newTrayMarkers: List[TrayMarker] = [] # in the new coord system
self.layout = QtWidgets.QVBoxLayout()
self.setLayout(self.layout)
selectionLayout = QtWidgets.QHBoxLayout()
self.trayMarkersBtn: QtWidgets.QRadioButton = QtWidgets.QRadioButton('Use Tray Markers')
self.trayMarkersBtn.pressed.connect(self._useTrayMarkers)
self.trayMarkersBtn.setChecked(True)
self.imgMarkersBtn: QtWidgets.QRadioButton = QtWidgets.QRadioButton('Use Image Markers')
self.imgMarkersBtn.pressed.connect(self._useImageMarkers)
selectionLayout.addWidget(self.trayMarkersBtn)
selectionLayout.addWidget(self.imgMarkersBtn)
self.addMarkerBtn: QtWidgets.QPushButton = QtWidgets.QPushButton('Add New Markers')
self.addMarkerBtn.setStyleSheet("background-color : lightgrey")
self._formatAsToggleBtn(self.addMarkerBtn)
self.transferResult: QtWidgets.QLabel = QtWidgets.QLabel('No valid input')
self.trayMarkerGroup: QtWidgets.QGroupBox = self._getTrayMarkerGroup()
self.imgMarkerGroup: QtWidgets.QGroupBox = self._getImageMarkerGroup()
saveBtn: QtWidgets.QPushButton = QtWidgets.QPushButton('Save to Dataset')
saveBtn.clicked.connect(self._saveToDataset)
self.layout.addLayout(selectionLayout)
self.layout.addWidget(self.trayMarkerGroup)
self.layout.addWidget(self.transferResult)
self.layout.addWidget(saveBtn)
self._getMarkersFromDataset()
def _getMarkersFromDataset(self) -> None:
if self.viewParent is not None:
self.trayMarkers = deepcopy(self.viewParent.dataset.trayMarkers)
self.imageMarkers = deepcopy(self.viewParent.dataset.imageMarkers)
for index, imgMarker in enumerate(self.imageMarkers):
pxPos: tuple = (imgMarker.imgCoordX, imgMarker.imgCoordY)
newMarkerWidget: CoordinateSystemMarker = CoordinateSystemMarker(index, pxPos)
self.imageMarkerWidgets.append(newMarkerWidget)
self.viewParent.scene().addItem(newMarkerWidget)
def _formatAsToggleBtn(self, btn: QtWidgets.QPushButton) -> None:
btn.setCheckable(True)
btn.setChecked(False)
btn.clicked.connect(lambda: self._setBtnColor(btn))
def _getTrayMarkerGroup(self) -> QtWidgets.QGroupBox:
layout = QtWidgets.QGridLayout()
group: QtWidgets.QGroupBox = QtWidgets.QGroupBox('Sample Tray Markers')
group.setLayout(layout)
if len(self.trayMarkers) == 0:
layout.addWidget(QtWidgets.QLabel('No tray markers found.'))
for i in range(3):
layout.addWidget(QtWidgets.QLabel('New Marker Placeholder'))
return group
def _getImageMarkerGroup(self) -> QtWidgets.QGroupBox:
def makeCenterOnLambda(ind):
return lambda: self._centerOnImageMarker(ind)
def makeDeleteLambda(ind):
return lambda: self._deleteImageMarker(ind)
def makeReadNewPosLambda(ind):
return lambda: self._readNewImageMarker(ind)
layout = QtWidgets.QGridLayout()
group: QtWidgets.QGroupBox = QtWidgets.QGroupBox('Image Based Markers')
group.setLayout(layout)
layout.addWidget(self.addMarkerBtn)
if len(self.imageMarkers) == 0:
layout.addWidget(QtWidgets.QLabel('No image markers found.'))
else:
layout.addWidget(QtWidgets.QLabel('Number'), 1, 0)
layout.addWidget(QtWidgets.QLabel('Coordinates old'), 1, 1)
layout.addWidget(QtWidgets.QLabel('Coordinates new'), 1, 2)
for index, imgMarker in enumerate(self.imageMarkers):
# reset indices, as they could have been reordered by deleting a marker..
imgMarker.index = index
self.imageMarkerWidgets[index].index = index
newMarker: ImageMarker = self.newImageMarkers[index]
newMarker.index = index
newX, newY, newZ = newMarker.worldCoordX, newMarker.worldCoordY, newMarker.worldCoordZ
x, y, z = imgMarker.worldCoordX, imgMarker.worldCoordY, imgMarker.worldCoordZ
row: int = 2+index
updateBtn: QtWidgets.QPushButton = QtWidgets.QPushButton('Read Coordinates')
updateBtn.clicked.connect(makeReadNewPosLambda(index))
focusBtn: QtWidgets.QPushButton = QtWidgets.QPushButton('Center On')
focusBtn.clicked.connect(makeCenterOnLambda(index))
delBtn: QtWidgets.QPushButton = QtWidgets.QPushButton('Delete')
delBtn.clicked.connect(makeDeleteLambda(index))
layout.addWidget(QtWidgets.QLabel(str(imgMarker.index+1)), row, 0)
layout.addWidget(QtWidgets.QLabel(f'x: {round(x)} µm\ny: {round(y)} µm\nz: {round(z)} µm'), row, 1)
if np.nan in [newX, newY, newZ]:
layout.addWidget(QtWidgets.QLabel('Coordinates not yet read.'), row, 2)
else:
layout.addWidget(QtWidgets.QLabel(f'x: {round(newX)} µm\ny: {round(newY)} µm\nz: {round(newZ)} µm'), row, 2)
layout.addWidget(updateBtn, row, 3)
layout.addWidget(focusBtn, row, 4)
layout.addWidget(delBtn, row, 5)
return group
def _updateTransferResult(self) -> None:
oldMarkers: list = self.trayMarkers if self.trayMarkersBtn.isChecked() else self.imageMarkers
newMarkers: list = self.newTrayMarkers if self.trayMarkersBtn.isChecked() else self.newImageMarkers
srcPoints: np.ndarray = np.array(
[[marker.worldCoordX, marker.worldCoordY, marker.worldCoordZ] for marker in oldMarkers])
dstPoints: np.ndarray = np.array(
[[marker.worldCoordX, marker.worldCoordY, marker.worldCoordZ] for marker in newMarkers])
hasNan: bool = (np.any(np.isnan(srcPoints)) or np.any(np.isnan(dstPoints)))
if len(oldMarkers) == len(newMarkers) and len(oldMarkers) >= 3 and not hasNan:
transformMatrix, pc, zpc, residuals = getTransform(srcPoints, dstPoints)
self.transferResult.setText(f'Transform residuals (µm): {residuals}')
else:
self.transferResult.setText('No valid inputs for coordinate transfer')
def _setBtnColor(self, btn: QtWidgets.QPushButton):
"""
Sets color of the toggle button to indicate its status.
"""
if btn.isChecked():
btn.setStyleSheet("background-color : lightblue")
else:
btn.setStyleSheet("background-color : lightgrey")
def _useTrayMarkers(self) -> None:
"""
Use markers on the sample tray that are NOT in the microscope image.
"""
self.imgMarkerGroup.setParent(None)
self.trayMarkerGroup.setParent(None)
self.trayMarkerGroup = self._getTrayMarkerGroup()
self.layout.insertWidget(1, self.trayMarkerGroup)
def _useImageMarkers(self) -> None:
"""
Use markers that are defined through characteristic spots within the microscope image.
"""
self.imgMarkerGroup.setParent(None)
self.trayMarkerGroup.setParent(None)
self.imgMarkerGroup = self._getImageMarkerGroup()
self.layout.insertWidget(1, self.imgMarkerGroup)
self._updateTransferResult()
def mousePressEvent(self, event: QtGui.QMouseEvent) -> None:
if self.addMarkerBtn.isChecked() and event.button() == QtCore.Qt.LeftButton:
scenePos = self.viewParent.mapToScene(event.pos())
self._addNewImageMarker((scenePos.x(), scenePos.y()))
def _deleteImageMarker(self, markerIndex: int) -> None:
self.imageMarkers.remove(self.imageMarkers[markerIndex])
self.newImageMarkers.remove(self.newImageMarkers[markerIndex])
self.viewParent.scene().removeItem(self.imageMarkerWidgets[markerIndex])
self.imageMarkerWidgets.remove(self.imageMarkerWidgets[markerIndex])
self._useImageMarkers()
def _centerOnImageMarker(self, markerIndex: int) -> None:
self.viewParent.centerOn(self.imageMarkerWidgets[markerIndex])
def _addNewImageMarker(self, pos: tuple) -> None:
newImageMarker: ImageMarker = ImageMarker()
newImageMarker.index = len(self.imageMarkers)
x, y, z = self.ramanctrl.getPosition()
newImageMarker.worldCoordX = x
newImageMarker.worldCoordY = y
newImageMarker.worldCoordZ = z
newImageMarker.imgCoordX = pos[0]
newImageMarker.imgCoordY = pos[1]
self.imageMarkers.append(newImageMarker)
newNewImageMarker: ImageMarker = ImageMarker()
newNewImageMarker.imgCoordX = pos[0]
newNewImageMarker.imgCoordY = pos[1]
self.newImageMarkers.append(newNewImageMarker)
newMarkerWidget: CoordinateSystemMarker = CoordinateSystemMarker(len(self.imageMarkers), pos)
self.imageMarkerWidgets.append(newMarkerWidget)
self.viewParent.scene().addItem(newMarkerWidget)
self._useImageMarkers()
def _readNewImageMarker(self, index: int) -> None:
"""Reads current instrument coordinates and assignes them to the respective "new image marker" """
x, y, z = self.ramanctrl.getPosition()
self.newImageMarkers[index].worldCoordX = x
self.newImageMarkers[index].worldCoordY = y
self.newImageMarkers[index].worldCoordZ = z
self._useImageMarkers()
def _saveToDataset(self) -> None:
if self.trayMarkersBtn.isChecked():
print('saving tray markers to dataset')
else:
print('saving image makers to dataset')
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
reply = QtWidgets.QMessageBox.question(self, 'Close without saving',
'The window is about to be closed.\nSave markers prior to closing?',
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.Yes)
if reply == QtWidgets.QMessageBox.Yes:
self._saveToDataset()
if self.viewParent is not None:
self.viewParent.showHiddenWidgets()
self.viewParent.coordTransferWidget = None
del self
class CoordinateSystemMarker(QtWidgets.QGraphicsItem):
def __init__(self, index: int, position: tuple):
super().__init__()
self.setPos(position[0], position[1])
self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
self.setCacheMode(QtWidgets.QGraphicsItem.DeviceCoordinateCache)
self.index = index
self.pxSize: int = 101
self.gapSize: int = 10
# self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges)
# self.poschanged = False
def boundingRect(self) -> QtCore.QRectF:
return QtCore.QRectF(-self.pxSize/2, -self.pxSize/2, self.pxSize, self.pxSize)
def paint(self, painter: QtGui.QPainter, option, widget) -> None:
halfSize: int = int(round(self.pxSize / 2))
halfGapSize: int = int(round(self.gapSize / 2))
painter.setPen(QtCore.Qt.green)
painter.setBrush(QtGui.QColor(30, 255, 30, 64))
painter.drawEllipse(-halfSize, -halfSize, self.pxSize, self.pxSize)
# horizontal lines
painter.drawLine(-halfSize, 0, -halfGapSize, 0)
painter.drawLine(halfGapSize, 0, halfSize, 0)
# vertical lines
painter.drawLine(0, -halfSize, 0, -halfGapSize)
painter.drawLine(0, halfGapSize, 0, halfSize)
painter.drawText(-halfSize, -halfSize, str(f'Marker {self.index+1}'))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
coordUI = CoordTransformUI(None)
coordUI.show()
ret = app.exec_()
...@@ -37,6 +37,7 @@ from .analysis.particleEditor import ParticleEditor ...@@ -37,6 +37,7 @@ from .analysis.particleEditor import ParticleEditor
from .ramancom.configRaman import RamanConfigWin from .ramancom.configRaman import RamanConfigWin
from .scenePyramid import ScenePyramid from .scenePyramid import ScenePyramid
from .gepardlogging import setDefaultLoggingConfig from .gepardlogging import setDefaultLoggingConfig
from .gui.coordTransferGUI import CoordTransformUI
class SampleView(QtWidgets.QGraphicsView): class SampleView(QtWidgets.QGraphicsView):
...@@ -83,7 +84,7 @@ class SampleView(QtWidgets.QGraphicsView): ...@@ -83,7 +84,7 @@ class SampleView(QtWidgets.QGraphicsView):
self.pyramid = ScenePyramid(self, self.logger) self.pyramid = ScenePyramid(self, self.logger)
self.particleEditor = None self.particleEditor = None
self.fititems = [] self.fititems = []
self.boundaryitems = [[],[]] self.boundaryitems = [[], []]
self.scanitems = [] self.scanitems = []
self.ramanscanitems = [] self.ramanscanitems = []
self.particleInfoBox = None self.particleInfoBox = None
...@@ -93,6 +94,7 @@ class SampleView(QtWidgets.QGraphicsView): ...@@ -93,6 +94,7 @@ class SampleView(QtWidgets.QGraphicsView):
self.selectedParticleIndices = [] self.selectedParticleIndices = []
self.seedPoints = [] self.seedPoints = []
self.particlePainter = None self.particlePainter = None
self.coordTransferWidget = None
self.detectionwidget = None self.detectionwidget = None
self.ramanwidget = RamanScanUI(self.ramanctrl, None, self.logger, self) self.ramanwidget = RamanScanUI(self.ramanctrl, None, self.logger, self)
...@@ -103,6 +105,7 @@ class SampleView(QtWidgets.QGraphicsView): ...@@ -103,6 +105,7 @@ class SampleView(QtWidgets.QGraphicsView):
self.setMinimumSize(600, 600) self.setMinimumSize(600, 600)
self.darkenPixmap = False self.darkenPixmap = False
self.microscopeMode = None self.microscopeMode = None
self.hiddenWidgets: list = []
self.update() self.update()
...@@ -141,10 +144,9 @@ class SampleView(QtWidgets.QGraphicsView): ...@@ -141,10 +144,9 @@ class SampleView(QtWidgets.QGraphicsView):
self.disconnectRaman() self.disconnectRaman()
self.saveDataSet() self.saveDataSet()
event.accept() event.accept()
self.oscanwidget.close() for widget in [self.oscanwidget, self.detectionwidget, self.ramanwidget, self.coordTransferWidget]:
if self.detectionwidget is not None: if widget is not None:
self.detectionwidget.close()