...
 
Commits (21)
...@@ -21,7 +21,7 @@ Requirements: ...@@ -21,7 +21,7 @@ Requirements:
for 64bit as many use cases require a lot of memory (16 GB better 32 GB for 64bit as many use cases require a lot of memory (16 GB better 32 GB
recommended) recommended)
* the tsp module in externalmodules can be built with * the tsp module in external can be built with
python setuptsp.py python setuptsp.py
please note: for this step a valid compiler needs to be installed in the please note: for this step a valid compiler needs to be installed in the
system; Otherwise use the precompiled tsp-module system; Otherwise use the precompiled tsp-module
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 16 12:43:00 2019
@author: brandt
"""
"""
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/>.
"""
import numpy as np
import cv2
from PyQt5 import QtWidgets
class ParticleEditor(object):
def __init__(self, datastats, parent):
self.datastats = datastats
self.parent = parent #the assigned analysis widget
self.backupFreq = 3 #save a backup every n actions
self.neverBackedUp = True
self.actionCounter = 0
def createSafetyBackup(self):
self.actionCounter += 1
if self.actionCounter == self.backupFreq-1 or self.neverBackedUp:
backupname = self.datastats.dataset.saveBackup()
print('backing up as', backupname)
self.neverBackedUp = False
self.actionCounter = 0
def getNewEntry(self):
text, okClicked = QtWidgets.QInputDialog.getText(self.parent.parent, "Custom assignment", "Enter new assignment")
if okClicked and text != '':
return text
def combineParticles(self, contourIndices, new_assignment):
if new_assignment == 'other':
new_assignment = self.getNewEntry()
if new_assignment is None:
return
contourIndices = sorted(contourIndices) #we want to keep the contour with lowest index
#get contours:
contours = [self.datastats.dataset.particlecontours[i] for i in contourIndices]
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 = 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))
for i in contourIndices:
curCnt = self.datastats.dataset.particlecontours[i].copy()
for i in range(len(curCnt)):
curCnt[i][0][0] -= xmin-padding
curCnt[i][0][1] -= ymin-padding
cv2.drawContours(img, [curCnt], -1, 1, -1)
cv2.drawContours(img, [curCnt], -1, 1, 1)
img = np.uint8(cv2.morphologyEx(img, cv2.MORPH_CLOSE, np.ones((3, 3))))
if cv2.__version__ > '3.5':
contours, hierarchy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
else:
temp, contours, hierarchy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
if len(contours)>1:
QtWidgets.QMessageBox.critical(self.parent, 'ERROR!',
'Particle contours are not connected and cannot be combined!')
return
newContour = contours[0]
stats = self.characterizeParticle(newContour)
for i in range(len(newContour)):
newContour[i][0][0] += xmin-padding
newContour[i][0][1] += ymin-padding
print('merging contours:', contourIndices)
self.createSafetyBackup()
#check, if dataset contains (already modified) particle2spectra, otherwise create new.
if self.datastats.dataset.particles2spectra is None: #create default assignment
print('recreating particles2spectra from within edit particles...')
sortindices = self.datastats.dataset.ramanscansortindex
self.datastats.dataset.particles2spectra = [[int(np.where(sortindices == i)[0])] for i in range(len(sortindices))]
#Contour indices are the same as the original particlestats, which are contained in the dataset.
#We have to modify that and reload in the analysisview
#first, overwrite first index with new particlestats
self.datastats.dataset.particlestats[contourIndices[0]] = stats
#now, delete the rest...
self.datastats.dataset.particlestats = [i for ind, i in enumerate(self.datastats.dataset.particlestats) if ind not in contourIndices[1:]]
#same with the contours
self.datastats.dataset.particlecontours[contourIndices[0]] = newContour
self.datastats.dataset.particlecontours = [i for ind, i in enumerate(self.datastats.dataset.particlecontours) if ind not in contourIndices[1:]]
#update particle2spectra_list
#what is the current particle index??
specIndices = []
#other spectra indices:
for index in contourIndices:
specIndices.append(self.datastats.particles2spectra[index])
#flatten index list (in case, that a nested list was created...)
specIndices = list(np.concatenate(specIndices))
for i in specIndices:
self.datastats.spectraResults[i] = new_assignment
self.datastats.hqis[i] = 100 #avoid sorting them out again by hqi-filter...
print(f'spectrum {i} of particle{contourIndices[0]} is now {new_assignment}')
#modify particles2spectra..
self.datastats.dataset.particles2spectra[contourIndices[0]] = specIndices
for index in reversed(contourIndices[1:]):
print('removing index from particles2spectra:', index)
del self.datastats.dataset.particles2spectra[index]
#update contours in sampleview
self.parent.parent.contouritem.resetContours(self.datastats.dataset.particlecontours)
self.parent.loadParticleData()
#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)
def reassignParticles(self, contourindices, new_assignment):
if new_assignment == 'other':
new_assignment = self.getNewEntry()
if new_assignment is None:
return
self.createSafetyBackup()
print(f'reassigning indices {contourindices} into {new_assignment}')
for partIndex in contourindices:
for specIndex in self.datastats.particles2spectra[partIndex]:
self.datastats.currentPolymers[specIndex] = new_assignment
self.datastats.spectraResults[specIndex] = new_assignment
self.datastats.hqis[specIndex] = 100
#update contours in sampleview
self.parent.parent.contouritem.resetContours(self.datastats.dataset.particlecontours)
self.parent.loadParticleData()
#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)
def deleteParticles(self):
self.createSafetyBackup()
pass
def splitParticles(self):
self.createSafetyBackup()
pass
def characterizeParticle(self, contours):
##characterize particle
longellipse, shortellipse = np.nan, np.nan
cnt = contours
if cnt.shape[0] >= 5: ##at least 5 points required for ellipse fitting...
ellipse = cv2.fitEllipse(cnt)
shortellipse, longellipse = ellipse[1]
rect = cv2.minAreaRect(cnt)
long, short = rect[1]
if short>long:
long, short = short, long
return long, short, longellipse, shortellipse, cv2.contourArea(cnt)
\ No newline at end of file
This diff is collapsed.
# -*- 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>
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, QtGui
import numpy as np
WX, WY = 1024, 200
class ColorLegend(QtWidgets.QMdiSubWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint|QtCore.Qt.FramelessWindowHint)
self.setFixedSize(200, 800)
self.wscale = 1
self.drag = None
self.items = [] #list of items to display (text, color)
self.tileSize = 12
self.fontSize = 15
self.spacer = 10
def setTextColorItems(self, items):
for text, color in items:
print(text, color)
assert type(text)==str or type(text)==np.str_, "items must be tuples of text and QColor"
assert type(color)==QtGui.QColor or type(color)==QtCore.Qt.GlobalColor, "items must be tuples of text and QColor"
self.items = items
self.update()
def mousePressEvent(self, event):
if event.button()==QtCore.Qt.LeftButton:
self.drag = event.pos()
def mouseMoveEvent(self, event):
if self.drag is not None:
p0 = event.pos()
self.move(self.mapToParent(p0-self.drag))
self.parentWidget().update()
else:
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.drag = None
super().mouseReleaseEvent(event)
def paintEvent(self, event):
numEntries = len(self.items)
if numEntries > 0:
def getSize(fontsize, text, tileSize, spacer):
font = QtGui.QFont()
font.setPixelSize(fontSize)
fm = QtGui.QFontMetrics(font)
pixelwidth = fm.width(text)
width, height = pixelwidth + tileSize + 4*spacer, numEntries * (fontSize+1*spacer) + spacer
return width, height
fontSize, tileSize, spacer = self.fontSize, self.tileSize, self.spacer
longestEntry = max([i[0] for i in self.items], key=len)
width, height = getSize(fontSize, longestEntry, tileSize, spacer)
# scale smaller, if necessary
if height > 1024:
factor = 1024/height
#prevent text getting tooo small:
factor = np.clip(factor, 0.6, 1) #0.6*15 would be fontSize 9
height, tileSize, fontSize, spacer = height*factor, tileSize*factor, int(fontSize*factor), spacer*factor
width, height = getSize(fontSize, longestEntry, tileSize, spacer)
self.setFixedSize(width, height)
qp = QtGui.QPainter()
qp.begin(self)
font = QtGui.QFont()
font.setPixelSize(fontSize)
qp.setFont(font)
for index, item in enumerate(self.items):
#draw Text
x0 = tileSize+2*spacer
y0 = index*(fontSize+spacer)
rect= QtCore.QRectF(x0, y0, width, float(fontSize+spacer))
qp.drawText(rect, QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter, item[0])
#draw colored Box
qp.setBrush(item[1])
x0 = spacer
y0 = index*(fontSize+spacer) + (fontSize - tileSize)/2 +spacer/2
qp.drawRect(x0, y0, tileSize, tileSize)
qp.end()
\ No newline at end of file
This diff is collapsed.
...@@ -267,7 +267,7 @@ class ImageView(QtWidgets.QLabel): ...@@ -267,7 +267,7 @@ class ImageView(QtWidgets.QLabel):
painter.drawEllipse(p[0]-p[2], p[1]-p[2], 2*p[2], 2*p[2]) painter.drawEllipse(p[0]-p[2], p[1]-p[2], 2*p[2], 2*p[2])
class ParticleDetectionView(QtWidgets.QWidget): class ParticleDetectionView(QtWidgets.QWidget):
imageUpdate = QtCore.pyqtSignal(name='imageUpdate') imageUpdate = QtCore.pyqtSignal(str, name='imageUpdate') #str = 'df' (= darkfield) or 'bf' (=bright field)
detectionFinished = QtCore.pyqtSignal(name='detectionFinished') detectionFinished = QtCore.pyqtSignal(name='detectionFinished')
def __init__(self, img, dataset, parent=None): def __init__(self, img, dataset, parent=None):
...@@ -275,8 +275,9 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -275,8 +275,9 @@ class ParticleDetectionView(QtWidgets.QWidget):
self.dataset = self.verifySeedpoints(dataset) self.dataset = self.verifySeedpoints(dataset)
self.img = img self.img = img
self.imgclip = 0,0,0,0 self.imgclip = 0,0,0,0
self.seg = Segmentation(self.dataset) self.seg = Segmentation(self.dataset, self)
self.thread = None self.thread = None
self.view = parent
vbox = QtWidgets.QVBoxLayout() vbox = QtWidgets.QVBoxLayout()
hbox = QtWidgets.QHBoxLayout() hbox = QtWidgets.QHBoxLayout()
...@@ -302,10 +303,12 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -302,10 +303,12 @@ class ParticleDetectionView(QtWidgets.QWidget):
group = QtWidgets.QGroupBox("Detection settings", self) group = QtWidgets.QGroupBox("Detection settings", self)
grid = QtWidgets.QGridLayout() grid = QtWidgets.QGridLayout()
self.parameters = [] self.parameters = []
checkBoxesToLink = {}
# create editable parameters: # create editable parameters:
for i, p in enumerate(self.seg.parlist): for i, p in enumerate(self.seg.parlist):
label, colstretch = None, 1 label, colstretch = None, 1
if p.name == "points": if p.name == "contrastCurve":
paramui = HistWidget(lambda : self.seg.calculateHist(self.seg.convert2Gray(self.subimg)), paramui = HistWidget(lambda : self.seg.calculateHist(self.seg.convert2Gray(self.subimg)),
self.seg.calculateHistFunction, self) self.seg.calculateHistFunction, self)
valuefunc = makeValueLambda(paramui.value) valuefunc = makeValueLambda(paramui.value)
...@@ -315,6 +318,8 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -315,6 +318,8 @@ class ParticleDetectionView(QtWidgets.QWidget):
paramui.setChecked(p.value) paramui.setChecked(p.value)
valuefunc = makeValueLambda(paramui.isChecked) valuefunc = makeValueLambda(paramui.isChecked)
colstretch = 2 colstretch = 2
if p.linkedParameter is not None:
checkBoxesToLink[paramui] = p.linkedParameter
elif p.dtype == int or p.dtype == float: elif p.dtype == int or p.dtype == float:
label = QtWidgets.QLabel(p.helptext, self) label = QtWidgets.QLabel(p.helptext, self)
if p.dtype == int: if p.dtype == int:
...@@ -333,18 +338,44 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -333,18 +338,44 @@ class ParticleDetectionView(QtWidgets.QWidget):
elif p.dtype is None: elif p.dtype is None:
label = QtWidgets.QLabel(p.helptext, self) label = QtWidgets.QLabel(p.helptext, self)
paramui = None paramui = None
if paramui is not None: if paramui is not None:
self.parameters.append([paramui, p.name, valuefunc]) self.parameters.append([paramui, p.name, valuefunc, None])
if colstretch == 1: if colstretch == 1:
grid.addWidget(paramui, i, 1, QtCore.Qt.AlignLeft) grid.addWidget(paramui, i, 1, QtCore.Qt.AlignLeft)
else: else:
grid.addWidget(paramui, i, 0, 1, 2, QtCore.Qt.AlignLeft) grid.addWidget(paramui, i, 0, 1, 2, QtCore.Qt.AlignLeft)
if label is not None: if label is not None:
grid.addWidget(label, i, 0, QtCore.Qt.AlignLeft) grid.addWidget(label, i, 0, QtCore.Qt.AlignLeft)
if p.show is True: if p.show is True:
pshow = QtWidgets.QPushButton(">", self) pshow = QtWidgets.QPushButton(">", self)
pshow.released.connect(makeShowLambda(p.name)) pshow.released.connect(makeShowLambda(p.name))
grid.addWidget(pshow, i, 2, QtCore.Qt.AlignRight) grid.addWidget(pshow, i, 2, QtCore.Qt.AlignRight)
if paramui is not None:
self.parameters[-1][3] = pshow
#link checkboxes to other parameters:
def makeEnableLambda(checkbox, parameter):
return lambda: parameter.setEnabled(checkbox.isChecked())
for box in checkBoxesToLink:
linkedName = checkBoxesToLink[box]
for p in self.parameters:
if p[1] == linkedName:
p[0].setEnabled(box.isChecked())
box.stateChanged.connect(makeEnableLambda(box, p[0])) #the actual control element
if p[3] is not None: #the "show" box, if present
box.stateChanged.connect(makeEnableLambda(box, p[3]))
p[3].setEnabled(box.isChecked())
label = QtWidgets.QLabel("Seed radius", self) label = QtWidgets.QLabel("Seed radius", self)
grid.addWidget(label, i+1, 0, QtCore.Qt.AlignLeft) grid.addWidget(label, i+1, 0, QtCore.Qt.AlignLeft)
...@@ -383,7 +414,7 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -383,7 +414,7 @@ class ParticleDetectionView(QtWidgets.QWidget):
def saveDetectParams(self, ds=None): def saveDetectParams(self, ds=None):
if ds is not None: if ds is not None:
for param in self.parameters: for param in self.parameters:
if param[1] == 'points': if param[1] == 'contrastCurve':
print(param[0].value()) print(param[0].value())
try: # is it a spinbox or the histWidget? Read out the value try: # is it a spinbox or the histWidget? Read out the value
ds.detectParams[param[1]] = param[0].value() ds.detectParams[param[1]] = param[0].value()
...@@ -462,7 +493,7 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -462,7 +493,7 @@ class ParticleDetectionView(QtWidgets.QWidget):
def closeEvent(self, event): def closeEvent(self, event):
self.detectionFinished.emit() self.detectionFinished.emit()
self.destroy() # self.destroy()
def mousePressEvent(self, event): def mousePressEvent(self, event):
if event.button()==QtCore.Qt.RightButton: if event.button()==QtCore.Qt.RightButton:
...@@ -534,7 +565,7 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -534,7 +565,7 @@ class ParticleDetectionView(QtWidgets.QWidget):
self.saveDetectParams(self.dataset) self.saveDetectParams(self.dataset)
img = self.subimg.copy() img = self.subimg.copy()
kwargs = {} kwargs = {}
for ui, name, valuefunc in self.parameters: for ui, name, valuefunc, showbtn in self.parameters:
kwargs[name] = valuefunc() kwargs[name] = valuefunc()
self.seg.setParameters(**kwargs) self.seg.setParameters(**kwargs)
seedradius = self.seedradiusedit.value() seedradius = self.seedradiusedit.value()
...@@ -561,7 +592,7 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -561,7 +592,7 @@ class ParticleDetectionView(QtWidgets.QWidget):
self.dataset.ramanscandone = False self.dataset.ramanscandone = False
self.dataset.mode = "opticalscan" self.dataset.mode = "opticalscan"
self.dataset.save() self.dataset.save()
self.imageUpdate.emit() self.imageUpdate.emit(self.view.microscopeMode)
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def cancelThread(self): def cancelThread(self):
...@@ -578,6 +609,9 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -578,6 +609,9 @@ class ParticleDetectionView(QtWidgets.QWidget):
self.pdetectsub.setEnabled(True) self.pdetectsub.setEnabled(True)
self.pclear.setEnabled(True) self.pclear.setEnabled(True)
def raiseWarning(self, warning):
QtWidgets.QMessageBox.critical(self, "Warning", warning)
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def detectParticles(self): def detectParticles(self):
self.saveDetectParams(self.dataset) self.saveDetectParams(self.dataset)
...@@ -602,7 +636,7 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -602,7 +636,7 @@ class ParticleDetectionView(QtWidgets.QWidget):
self.thread = None self.thread = None
self.unBlockUI() self.unBlockUI()
self.pdetectall.setText("Detect all") self.pdetectall.setText("Detect all")
self.imageUpdate.emit() self.imageUpdate.emit(self.view.microscopeMode)
if self.dataset is not None: if self.dataset is not None:
self.setWindowTitle(str(len(self.dataset.ramanpoints)) + " Particles") self.setWindowTitle(str(len(self.dataset.ramanpoints)) + " Particles")
else: else:
...@@ -614,7 +648,7 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -614,7 +648,7 @@ class ParticleDetectionView(QtWidgets.QWidget):
if self.dataset is not None: if self.dataset is not None:
seedpoints = self.dataset.seedpoints seedpoints = self.dataset.seedpoints
deletepoints = self.dataset.seeddeletepoints deletepoints = self.dataset.seeddeletepoints
for ui, name, valuefunc in self.parameters: for ui, name, valuefunc, showbtn in self.parameters:
kwargs[name] = valuefunc() kwargs[name] = valuefunc()
seedradius = self.seedradiusedit.value() seedradius = self.seedradiusedit.value()
self.seg.setParameters(**kwargs) self.seg.setParameters(**kwargs)
......
...@@ -21,25 +21,34 @@ If not, see <https://www.gnu.org/licenses/>. ...@@ -21,25 +21,34 @@ If not, see <https://www.gnu.org/licenses/>.
from PyQt5 import QtCore, QtWidgets, QtGui from PyQt5 import QtCore, QtWidgets, QtGui
from sampleview import SampleView from sampleview import SampleView
from scalebar import ScaleBar from scalebar import ScaleBar
from ramancontrol import defaultPath from ramancom.ramancontrol import defaultPath
from ramancom.ramanSwitch import RamanSwitch
from colorlegend import ColorLegend
import os import os
class MeasureParticleWindow(QtWidgets.QMainWindow): class MeasureParticleWindow(QtWidgets.QMainWindow):
def __init__(self): def __init__(self, logpath):
super(MeasureParticleWindow, self).__init__() super(MeasureParticleWindow, self).__init__()
self.setWindowTitle("GEPARD") self.setWindowTitle("GEPARD")
self.resize(900, 700) self.resize(900, 700)
self.view = SampleView() self.view = SampleView(logpath)
self.view.imparent = self self.view.imparent = self
self.view.ScalingChanged.connect(self.scalingChanged) self.view.ScalingChanged.connect(self.scalingChanged)
self.scalebar = ScaleBar(self) self.scalebar = ScaleBar(self)
self.legend = ColorLegend(self)
self.ramanSwitch = RamanSwitch(self)
self.view.ScalingChanged.connect(self.scalebar.updateScale) self.view.ScalingChanged.connect(self.scalebar.updateScale)
mdiarea = QtWidgets.QMdiArea(self) mdiarea = QtWidgets.QMdiArea(self)
mdiarea.addSubWindow(self.scalebar) mdiarea.addSubWindow(self.scalebar)
mdiarea.addSubWindow(self.legend)
mdiarea.addSubWindow(self.ramanSwitch)
self.legend.hide()
self.ramanSwitch.hide()
subview = mdiarea.addSubWindow(self.view) subview = mdiarea.addSubWindow(self.view)
subview.showMaximized() subview.showMaximized()
subview.setWindowFlags(QtCore.Qt.FramelessWindowHint) subview.setWindowFlags(QtCore.Qt.FramelessWindowHint)
...@@ -53,7 +62,9 @@ class MeasureParticleWindow(QtWidgets.QMainWindow): ...@@ -53,7 +62,9 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
self.updateModes() self.updateModes()
def resizeEvent(self, event): def resizeEvent(self, event):
self.scalebar.move(0,self.height()-self.scalebar.height()) 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)
def closeEvent(self, event): def closeEvent(self, event):
self.view.closeEvent(event) self.view.closeEvent(event)
...@@ -73,6 +84,16 @@ class MeasureParticleWindow(QtWidgets.QMainWindow): ...@@ -73,6 +84,16 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
self.fname = str(fileName) self.fname = str(fileName)
self.view.open(self.fname) self.view.open(self.fname)
self.scalingChanged(1.) self.scalingChanged(1.)
@QtCore.pyqtSlot()
def importProject(self, fileName=False):
if fileName is False:
fileName = QtWidgets.QFileDialog.getOpenFileName(self, "Import Zeiss Zen Project",
defaultPath, "*.xml")[0]
if fileName:
self.fname = str(fileName)
self.view.importProject(self.fname)
self.scalingChanged(1.)
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def new(self, fileName=False): def new(self, fileName=False):
...@@ -80,9 +101,12 @@ class MeasureParticleWindow(QtWidgets.QMainWindow): ...@@ -80,9 +101,12 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
fileName = QtWidgets.QFileDialog.getSaveFileName(self, "Create New Project", fileName = QtWidgets.QFileDialog.getSaveFileName(self, "Create New Project",
defaultPath, "*.pkl")[0] defaultPath, "*.pkl")[0]
if fileName: if fileName:
self.fname = str(fileName) if fileName.find(' ') < 0:
self.view.new(self.fname) self.fname = str(fileName)
self.scalingChanged(1.) self.view.new(self.fname)
self.scalingChanged(1.)
else:
QtWidgets.QMessageBox.critical(self, "Error", "File path must not contain spaces.")
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def about(self): def about(self):
...@@ -101,6 +125,10 @@ class MeasureParticleWindow(QtWidgets.QMainWindow): ...@@ -101,6 +125,10 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
self.openAct.setShortcut("Ctrl+O") self.openAct.setShortcut("Ctrl+O")
self.openAct.triggered.connect(self.open) self.openAct.triggered.connect(self.open)
self.importAct = QtWidgets.QAction("&Import Project...", self)
self.importAct.setShortcut("Ctrl+I")
self.importAct.triggered.connect(self.importProject)
self.newAct = QtWidgets.QAction("&New Measurement...", self) self.newAct = QtWidgets.QAction("&New Measurement...", self)
self.newAct.setShortcut("Ctrl+N") self.newAct.setShortcut("Ctrl+N")
self.newAct.triggered.connect(self.new) self.newAct.triggered.connect(self.new)
...@@ -152,13 +180,20 @@ class MeasureParticleWindow(QtWidgets.QMainWindow): ...@@ -152,13 +180,20 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
self.ramanScanAct.setCheckable(True) self.ramanScanAct.setCheckable(True)
self.ramanScanAct.triggered.connect(QtCore.pyqtSlot()(lambda :self.view.switchMode("RamanScan"))) self.ramanScanAct.triggered.connect(QtCore.pyqtSlot()(lambda :self.view.switchMode("RamanScan")))
self.particelAnalysisAct = QtWidgets.QAction("Particle analysis", self) self.particelAnalysisAct = QtWidgets.QAction("Particle analysis", self)
self.particelAnalysisAct.setEnabled(False) self.particelAnalysisAct.setEnabled(False)
self.particelAnalysisAct.setCheckable(True) self.particelAnalysisAct.setCheckable(True)
self.particelAnalysisAct.triggered.connect(QtCore.pyqtSlot()(lambda :self.view.switchMode("ParticleAnalysis"))) self.particelAnalysisAct.triggered.connect(QtCore.pyqtSlot()(lambda :self.view.switchMode("ParticleAnalysis")))
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.triggered.connect(self.view.configureRamanControl)
if self.view.simulatedRaman:
self.configRamanCtrlAct.setDisabled(True)
def updateModes(self, active=None, maxenabled=None): def updateModes(self, active=None, maxenabled=None):
ose, osc, pde, pdc, rse, rsc, pae, pac = [False]*8 ose, osc, pde, pdc, rse, rsc, pae, pac = [False]*8
if maxenabled=="OpticalScan": if maxenabled=="OpticalScan":
...@@ -190,12 +225,14 @@ class MeasureParticleWindow(QtWidgets.QMainWindow): ...@@ -190,12 +225,14 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
def unblockUI(self, connected): def unblockUI(self, connected):
self.openAct.setEnabled(True) self.openAct.setEnabled(True)
self.importAct.setEnabled(True)
self.newAct.setEnabled(True) self.newAct.setEnabled(True)
self.updateConnected(connected) self.updateConnected(connected)
self.exitAct.setEnabled(True) self.exitAct.setEnabled(True)
def blockUI(self): def blockUI(self):
self.openAct.setEnabled(False) self.openAct.setEnabled(False)
self.importAct.setEnabled(False)
self.newAct.setEnabled(False) self.newAct.setEnabled(False)
self.connectRamanAct.setEnabled(False) self.connectRamanAct.setEnabled(False)
self.disconnectRamanAct.setEnabled(False) self.disconnectRamanAct.setEnabled(False)
...@@ -216,10 +253,11 @@ class MeasureParticleWindow(QtWidgets.QMainWindow): ...@@ -216,10 +253,11 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
def createMenus(self): def createMenus(self):
self.fileMenu = QtWidgets.QMenu("&File", self) self.fileMenu = QtWidgets.QMenu("&File", self)
self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.newAct)
self.fileMenu.addAction(self.importAct)
self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.openAct)
self.fileMenu.addSeparator() self.fileMenu.addSeparator()
self.fileMenu.addAction(self.exitAct) self.fileMenu.addAction(self.exitAct)
self.viewMenu = QtWidgets.QMenu("&View", self) self.viewMenu = QtWidgets.QMenu("&View", self)
self.viewMenu.addAction(self.zoomInAct) self.viewMenu.addAction(self.zoomInAct)
self.viewMenu.addAction(self.zoomOutAct) self.viewMenu.addAction(self.zoomOutAct)
...@@ -232,19 +270,26 @@ class MeasureParticleWindow(QtWidgets.QMainWindow): ...@@ -232,19 +270,26 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
self.modeMenu.addAction(self.detectParticleAct) self.modeMenu.addAction(self.detectParticleAct)
self.modeMenu.addAction(self.particelAnalysisAct) self.modeMenu.addAction(self.particelAnalysisAct)
self.toolsMenu = QtWidgets.QMenu("&Tools")
self.toolsMenu.addAction(self.snapshotAct)
self.toolsMenu.addAction(self.configRamanCtrlAct)
self.helpMenu = QtWidgets.QMenu("&Help", self) self.helpMenu = QtWidgets.QMenu("&Help", self)
self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutAct)
self.menuBar().addMenu(self.fileMenu) self.menuBar().addMenu(self.fileMenu)
self.menuBar().addMenu(self.viewMenu) self.menuBar().addMenu(self.viewMenu)
self.menuBar().addMenu(self.modeMenu) self.menuBar().addMenu(self.modeMenu)
self.menuBar().addMenu(self.toolsMenu)
self.menuBar().addMenu(self.helpMenu) self.menuBar().addMenu(self.helpMenu)
def createToolBar(self): def createToolBar(self):
self.toolbar = QtWidgets.QToolBar("Tools") self.toolbar = QtWidgets.QToolBar("Tools")
self.toolbar.setIconSize(QtCore.QSize(100,50)) self.toolbar.setIconSize(QtCore.QSize(100,50))
self.toolbar.addAction(self.aboutAct) self.toolbar.addAction(self.aboutAct)
self.toolbar.addAction(self.newAct) self.toolbar.addAction(self.newAct)
self.toolbar.addAction(self.importAct)
self.toolbar.addAction(self.openAct) self.toolbar.addAction(self.openAct)
self.toolbar.addSeparator() self.toolbar.addSeparator()
self.toolbar.addAction(self.connectRamanAct) self.toolbar.addAction(self.connectRamanAct)
...@@ -260,16 +305,29 @@ class MeasureParticleWindow(QtWidgets.QMainWindow): ...@@ -260,16 +305,29 @@ class MeasureParticleWindow(QtWidgets.QMainWindow):
self.addToolBar(QtCore.Qt.LeftToolBarArea, self.toolbar) self.addToolBar(QtCore.Qt.LeftToolBarArea, self.toolbar)
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
from time import localtime, strftime from time import localtime, strftime
logname = os.path.join(os.path.split(__file__)[0], os.path.join("logfile.txt"))
fp = open(logname, "a")
sys.stderr = fp
sys.stdout = fp
print("starting GEPARD at: " + strftime("%d %b %Y %H:%M:%S", localtime()))
app = QtWidgets.QApplication(sys.argv) app = QtWidgets.QApplication(sys.argv)
meas = MeasureParticleWindow() app.setApplicationName("GEPARD") # appname needed for logpath
logpath = QtCore.QStandardPaths.writableLocation(
QtCore.QStandardPaths.AppLocalDataLocation)
fp = None
if logpath != "":
if not os.path.exists(logpath):
os.mkdir(logpath)
logname = os.path.join(logpath, 'logfile.txt')
fp = open(logname, "a")
sys.stderr = fp
sys.stdout = fp
print("starting GEPARD at: " + strftime("%d %b %Y %H:%M:%S", localtime()),
flush=True)
meas = MeasureParticleWindow(logpath)
meas.showMaximized() meas.showMaximized()
ret = app.exec_() ret = app.exec_()
\ No newline at end of file if fp is not None:
fp.close()
\ No newline at end of file
...@@ -24,15 +24,11 @@ import cv2 ...@@ -24,15 +24,11 @@ import cv2
import os import os
def cv2imread_fix(fname, flags=cv2.IMREAD_COLOR): def cv2imread_fix(fname, flags=cv2.IMREAD_COLOR):
if not os.path.exists(fname): #This seems to be a source of potential errors. Having these lines here probably aids finding errors for other groups? with open(fname, "rb") as fp:
print('Error, image file not found\Please check if the used save-Image command returns before the image was fully written to disk.') cont = fp.read()
return img = cv2.imdecode(np.fromstring(cont, dtype=np.uint8), flags)
return img
with open(fname, "rb") as fp: return None
cont = fp.read()
img = cv2.imdecode(np.fromstring(cont, dtype=np.uint8), flags)
return img
return None
def cv2imwrite_fix(fname, img, params=None): def cv2imwrite_fix(fname, img, params=None):
pathname, ext = os.path.splitext(fname) pathname, ext = os.path.splitext(fname)
......
This diff is collapsed.
...@@ -28,12 +28,23 @@ except ImportError: ...@@ -28,12 +28,23 @@ except ImportError:
os.environ["NO_WITEC_CONTROL"] = "True" os.environ["NO_WITEC_CONTROL"] = "True"
from time import sleep, time from time import sleep, time
from ramanbase import RamanBase try: #when running the witectesting, the paths have to be differently, as it is in the same directory as the other raman com modules
from ramancom.ramanbase import RamanBase
from ramancom.configRaman import RamanSettingParam
except:
from ramanbase import RamanBase
from configRaman import RamanSettingParam
from socket import gethostname from socket import gethostname
class WITecCOM(RamanBase): class WITecCOM(RamanBase):
CLSID = "{C45E77CE-3D66-489A-B5E2-159F443BD1AA}" CLSID = "{C45E77CE-3D66-489A-B5E2-159F443BD1AA}"
magn = 20
ramanParameters = [RamanSettingParam('IntegrationTime (s)', 'double', default=0.5, minVal=0.01, maxVal=100),
RamanSettingParam('Accumulations', 'int', default=5, minVal=1, maxVal=100)]
def __init__(self, hostname=None): def __init__(self, hostname=None):
super().__init__() super().__init__()
if hostname is None: if hostname is None:
...@@ -193,7 +204,7 @@ class WITecCOM(RamanBase): ...@@ -193,7 +204,7 @@ class WITecCOM(RamanBase):
z = self.PosZCurUserFloatMan.GetSingleValueAsDouble()[1] z = self.PosZCurUserFloatMan.GetSingleValueAsDouble()[1]
return z return z
def moveToAbsolutePosition(self, x, y, z=None, epsxy=0.11, epsz=0.011): def moveToAbsolutePosition(self, x, y, z=None, epsxy=0.11, epsz=0.011, debugReturn=False, measurementRunning=False):
assert self.connected assert self.connected
initpos = self.getPosition() initpos = self.getPosition()
# move only if new position is really different; repeat if new position is ignored (happens some times) # move only if new position is really different; repeat if new position is ignored (happens some times)
...@@ -208,9 +219,8 @@ class WITecCOM(RamanBase): ...@@ -208,9 +219,8 @@ class WITecCOM(RamanBase):
while distance > epsxy:# and (lastpos is None or lastpos!=curpos): while distance > epsxy:# and (lastpos is None or lastpos!=curpos):
curpos = self.getPosition() curpos = self.getPosition()
distance = max(abs(curpos[0]-x), abs(curpos[1]-y)) distance = max(abs(curpos[0]-x), abs(curpos[1]-y))
# if ((time()-t0>0.5) and max(abs(curpos[0]-initpos[0]), abs(curpos[1]-initpos[1]))<epsxy) or (time()-t0>10.): if ((time()-t0>0.5) and max(abs(curpos[0]-initpos[0]), abs(curpos[1]-initpos[1]))<epsxy) or (time()-t0>10.):
if ((time()-t0>2) and max(abs(curpos[0]-initpos[0]), abs(curpos[1]-initpos[1]))<epsxy) or (time()-t0>10.): print("WARNING: signal ignored:", time()-t0, x, y, curpos, initpos)
print("WARNING: signal ignored; time: {} s, x, y: {}, {}, curPos: {}, initPos: {}".format((time()-t0), x, y, curpos, initpos))
sys.stdout.flush() sys.stdout.flush()
break break
sleep(.01) sleep(.01)
...@@ -244,7 +254,7 @@ class WITecCOM(RamanBase): ...@@ -244,7 +254,7 @@ class WITecCOM(RamanBase):
self.ImageSaveMan.OperateTrigger() self.ImageSaveMan.OperateTrigger()
sleep(.1) sleep(.1)
def getImageDimensions(self): def getImageDimensions(self, mode = 'df'):
""" Get the image width and height in um and the orientation angle in degrees. """ Get the image width and height in um and the orientation angle in degrees.
""" """
assert self.connected assert self.connected
...@@ -262,16 +272,17 @@ class WITecCOM(RamanBase): ...@@ -262,16 +272,17 @@ class WITecCOM(RamanBase):
if not Busy: if not Busy:
break break
def initiateTimeSeriesScan(self, label, numberofscans, accumulations, integrtime): def initiateMeasurement(self, ramanSettings):
assert self.connected assert self.connected
self.timeseries = numberofscans self.timeseries = ramanSettings['numPoints']
self.TimeSeriesSlowNameMan.SetValue(label) self.TimeSeriesSlowNameMan.SetValue(ramanSettings['filename'])
self.TimeSeriesSlowNumMeasurementsMan.SetValue(numberofscans) self.TimeSeriesSlowNumMeasurementsMan.SetValue(ramanSettings['numPoints'])
self.TimeSeriesSlowNumAccumulationsMan.SetValue(accumulations) self.TimeSeriesSlowNumAccumulationsMan.SetValue(ramanSettings['Accumulations'])
self.TimeSeriesSlowIntTimeMan.SetValue(integrtime) self.TimeSeriesSlowIntTimeMan.SetValue(ramanSettings['IntegrationTime (s)'])
self.TimeSeriesSlowModeMan.SetValueNumeric(0) self.TimeSeriesSlowModeMan.SetValueNumeric(0)
self.TimeSeriesSlowNumMan.SetValue(0) self.TimeSeriesSlowNumMan.SetValue(0)
self.TimeSeriesSlowStartMan.OperateTrigger() self.TimeSeriesSlowStartMan.OperateTrigger()
sleep(0.1) sleep(0.1)
t1 = time() t1 = time()
while True: while True:
...@@ -286,7 +297,7 @@ class WITecCOM(RamanBase): ...@@ -286,7 +297,7 @@ class WITecCOM(RamanBase):
t1 = time() t1 = time()
def nextTimeSeriesScan(self, num): def triggerMeasurement(self, num):
assert self.timeseries assert self.timeseries
self.TimeSeriesSlowNextMan.OperateTrigger() self.TimeSeriesSlowNextMan.OperateTrigger()
# Wait until sequencer has finished # Wait until sequencer has finished
...@@ -313,4 +324,5 @@ class WITecCOM(RamanBase): ...@@ -313,4 +324,5 @@ class WITecCOM(RamanBase):
if num==self.timeseries-1: if num==self.timeseries-1:
self.timeseries = False self.timeseries = False
def finishMeasurement(self):
\ No newline at end of file pass
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Sep 21 12:23:20 2018
@author: brandt
"""
from PyQt5 import QtWidgets
class RamanConfigWin(QtWidgets.QWidget):
def __init__(self, parent=None):
super(RamanConfigWin, self).__init__()
self.parent = parent
if parent is not None:
self.ramancontrol = self.parent.ramanctrl
self.setGeometry(200, 200, 400, 300)
self.setWindowTitle('Configure Raman Control')
layout = QtWidgets.QGridLayout()
self.setLayout(layout)
generalGroup = QtWidgets.QGroupBox('General settings')
witecGroup = QtWidgets.QGroupBox('WITec settings')
renishawGroup = QtWidgets.QGroupBox('Renishaw settings')
generalLayout = QtWidgets.QFormLayout()
self.magnSpinBox = QtWidgets.QSpinBox()
if parent is not None:
self.magnSpinBox.setValue(self.ramancontrol.magn)
else:
self.magnSpinBox.setValue(20)
generalLayout.addRow(QtWidgets.QLabel('Magnification (x)'), self.magnSpinBox)
generalGroup.setLayout(generalLayout)
witecLayout = QtWidgets.QFormLayout()
witecLayout.addRow(QtWidgets.QLabel('Nothing yet implemented...'))
witecGroup.setLayout(witecLayout)
renishawLayout = QtWidgets.QFormLayout()
self.ren_BFwidth = QtWidgets.QDoubleSpinBox()
self.ren_BFheight = QtWidgets.QDoubleSpinBox()
self.ren_DFwidth = QtWidgets.QDoubleSpinBox()
self.ren_DFheight = QtWidgets.QDoubleSpinBox()
for spinbox in [self.ren_BFheight, self.ren_BFwidth, self.ren_DFheight, self.ren_DFwidth]:
spinbox.setMinimum(0)
spinbox.setMaximum(1e7)
if self.parent is not None:
self.ren_BFwidth.setValue(self.ramancontrol.cam_bf_dims[0])
self.ren_BFheight.setValue(self.ramancontrol.cam_bf_dims[1])
self.ren_DFwidth.setValue(self.ramancontrol.cam_df_dims[0])
self.ren_DFheight.setValue(self.ramancontrol.cam_df_dims[1])
self.getBFImgDimBtn = QtWidgets.QPushButton('Read dimensions from File')
self.getBFImgDimBtn.released.connect(self.makeReadImgDimsLambda(self.ren_BFwidth, self.ren_BFheight))
self.getDFImgDimBtn = QtWidgets.QPushButton('Read dimensions from File')
self.getDFImgDimBtn.released.connect(self.makeReadImgDimsLambda(self.ren_DFwidth, self.ren_DFheight))
renishawLayout.addRow(QtWidgets.QLabel('Bright Field Camera Settings'))
renishawLayout.addRow(QtWidgets.QLabel('Image widht (um)'), self.ren_BFwidth)
renishawLayout.addRow(QtWidgets.QLabel('Image height (um)'), self.ren_BFheight)
renishawLayout.addRow(self.getBFImgDimBtn)
renishawLayout.addRow(QtWidgets.QLabel())
renishawLayout.addRow(QtWidgets.QLabel('Dark Field Camera Settings'))
renishawLayout.addRow(QtWidgets.QLabel('Image widht (um)'), self.ren_DFwidth)
renishawLayout.addRow(QtWidgets.QLabel('Image height (um)'), self.ren_DFheight)
renishawLayout.addRow(self.getDFImgDimBtn)
renishawGroup.setLayout(renishawLayout)
layout.addWidget(generalGroup, 0, 0, 1, 2)
layout.addWidget(witecGroup, 1, 0)
layout.addWidget(renishawGroup, 1, 1)
closeBtn = QtWidgets.QPushButton('Save and Exit')
closeBtn.released.connect(self.close)
layout.addWidget(closeBtn, 2, 0)
def makeReadImgDimsLambda(self, width_spinbox, height_spinbox):
return lambda: self.readImgDims(width_spinbox, height_spinbox)
def readImgDims(self, width_spinbox, height_spinbox):
try:
import exifread
except:
QtWidgets.QMessageBox.critical(self, 'Error', 'Failed to load exifread module!\nPlease install exifread module to use this function')
return
magn, ok = QtWidgets.QInputDialog.getInt(self, 'Enter Magnification', 'Magnification = ', 20)
if not ok:
return
fname = QtWidgets.QFileDialog.getOpenFileName(self, 'Select jpeg file', 'C://', 'Image file (*.jpg *.jpeg)')[0]
if len(fname) == 0:
return
def stringDivision(string):
a, b = string.split('/')
a, b = float(a), float(b)
return a/b
try:
file = open(fname, 'rb')
tags = exifread.process_file(file)
for index, key in enumerate(tags):
if index == 3:
startVals = tags[key].printable
if index == 4:
ranges = tags[key].printable
startVals = startVals.replace('[', '').replace(']', '').replace(' ', '') #remove brackets and space
ranges = ranges.replace('[', '').replace(']', '').replace(' ', '') #remove brackets and space
startX, startY = startVals.split(',')
rangeX, rangeY = ranges.split(',')
startX, startY = stringDivision(startX), stringDivision(startY)
rangeX, rangeY = stringDivision(rangeX), stringDivision(rangeY)
width_spinbox.setValue(rangeX*magn)
height_spinbox.setValue(rangeY*magn)
except:
QtWidgets.QMessageBox.critical(self, 'Error', 'Reading dimensions from jpeg failed')
def closeEvent(self, event):
ret = QtWidgets.QMessageBox.question(self, '', 'Save Data to RamanControl?', QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.Yes)
if ret == QtWidgets.QMessageBox.Yes:
if self.parent is not None:
if self.ramancontrol.hostname == 'AN-Raman-Renishaw':
self.ramancontrol.cam_bf_dims = [self.ren_BFwidth.value(), self.ren_BFheight.value()]
self.ramancontrol.cam_df_dims = [self.ren_DFwidth.value(), self.ren_DFheight.value()]
self.ramancontrol.magn = self.magnSpinBox.value()
else:
print('fake saved')
class RamanSettingParam(object):
def __init__(self, name, dtype, default=None, minVal=None, maxVal=None, valList=None, openFileType=None):
self.name = name
self.dtype = dtype
self.value = default
self.minVal = minVal
self.maxVal = maxVal
self.valList = valList
self.openFileType = openFileType
if not self.hasValidType():
print('erroreneous type in setting parameter:', self.dtype)
def hasValidType(self):
if self.dtype in ['int', 'double', 'checkBox', 'combobox', 'selectBtn']:
return True
else:
return False
def value_of(self, obj):
if self.dtype in ['int', 'double']:
return obj.value()
elif self.dtype == 'checkBox':
return obj.isChecked()
elif self.dtype == 'combobox':
return obj.currentText()
elif self.dtype == 'selectBtn':
return obj.text()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
setWin = RamanConfigWin()
setWin.show()
ret = app.exec_()
\ No newline at end of file
import sys, os
from PyQt5 import QtWidgets, QtCore
class RamanSwitch(QtWidgets.QMdiSubWindow):
def __init__(self, parent=None):
super(RamanSwitch, self).__init__()
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint|QtCore.Qt.FramelessWindowHint)
self.setFixedSize(220, 60)
self.parent = parent
self.sampleview = None
layout = self.layout()
self.df_btn = QtWidgets.QRadioButton('Darkfield')
self.bf_btn = QtWidgets.QRadioButton('Brightfield')
self.bf_btn.setChecked(True)
self.df_btn.clicked.connect(self.updateMode)
self.bf_btn.clicked.connect(self.updateMode)
groupLayout = QtWidgets.QHBoxLayout()
group = QtWidgets.QGroupBox('Micropscope Mode')
groupLayout.addWidget(self.bf_btn)
groupLayout.addWidget(self.df_btn)
group.setLayout(groupLayout)
layout.addWidget(group)
def connectToSampleView(self):
if self.parent is not None:
self.sampleview = self.parent.view
if os.path.exists(self.sampleview.dataset.getImageName()):
mode = self.sampleview.dataset.imagescanMode
print('fullimage was acquired in', mode)
if mode == 'df':
self.df_btn.setChecked(True)
else:
self.df_btn.setChecked(False)
self.setDisabled(True)
def updateMode(self):
if self.sampleview is not None:
if self.df_btn.isChecked():
self.sampleview.microscopeMode = 'df'
self.sampleview.announceScaling()
else:
self.sampleview.microscopeMode = 'bf'
self.sampleview.announceScaling()
print('mic-mode is now', self.sampleview.microscopeMode)
#class QSlideSwitchPrivate(QtCore.QObject):
#
# def __init__(self, q):
# super(QSlideSwitchPrivate, self).__init__()
#
# self._position = 0
# self._sliderShape = QtCore.QRectF()
# self._gradient = QtGui.QLinearGradient()
# self._gradient.setSpread(QtGui.QGradient.PadSpread)
# self._qPointer = q
#
# self.animation = QtCore.QPropertyAnimation(self)
# self.animation.setTargetObject(self)
# self.animation.setPropertyName(b"position")
# self.animation.setStartValue(0)
# self.animation.setEndValue(1)
# self.animation.setDuration(300)
# self.animation.setEasingCurve(QtCore.QEasingCurve.InOutExpo)
#
# def __del__(self):
# del self.animation
#
# @QtCore.pyqtProperty(float)
# def position(self):
# return self._position
#
# @position.setter
# def position(self, value):
# self._position = value
# self._qPointer.repaint()
#
# def drawSlider(self, painter):
# margin = 3
# r = self._qPointer.rect().adjusted(0,0,-1,-1)
# dx = (r.width() - self._sliderShape.width()) * self._position
# sliderRect = self._sliderShape.translated(dx, 0)
# painter.setPen(QtCore.Qt.NoPen)
#
# # basic settings
# shadow = self._qPointer.palette().color(QtGui.QPalette.Dark)
# light = self._qPointer.palette().color(QtGui.QPalette.Light)
# button = self._qPointer.palette().color(QtGui.QPalette.Button)
#
# # draw background
# # draw outer background
# self._gradient.setColorAt(0, shadow.darker(130))
# self._gradient.setColorAt(1, light.darker(130))
# self._gradient.setStart(0, r.height())
# self._gradient.setFinalStop(0, 0)
# painter.setBrush(self._gradient)
# painter.drawRoundedRect(r, 15, 15)
#
# # draw background
# # draw inner background
# self._gradient.setColorAt(0, shadow.darker(140))
# self._gradient.setColorAt(1, light.darker(160))
# self._gradient.setStart(0, 0)
# self._gradient.setFinalStop(0, r.height())
# painter.setBrush(self._gradient)
# painter.drawRoundedRect(r.adjusted(margin, margin, -margin, -margin), 15, 15)
#
# # draw slider
# self._gradient.setColorAt(0, button.darker(130))
# self._gradient.setColorAt(1, button)
#
# # draw outer slider
# self._gradient.setStart(0, r.height())
# self._gradient.setFinalStop(0, 0)
# painter.setBrush(self._gradient)
# painter.drawRoundedRect(sliderRect.adjusted(margin, margin, -margin, -margin), 10, 15)
#
# # draw inner slider
# self._gradient.setStart(0, 0)
# self._gradient.setFinalStop(0, r.height())
# painter.setBrush(self._gradient)
# painter.drawRoundedRect(sliderRect.adjusted(2.5 * margin, 2.5 * margin, -2.5 * margin, - 2.5 * margin), 5, 15)
#
# font = self._qPointer.font()
# self._gradient.setColorAt(0, light)
# self._gradient.setColorAt(1, shadow)
# self._gradient.setStart(0, r.height() / 2.0 + font.pointSizeF())
# self._gradient.setFinalStop(0, r.height() / 2.0 - font.pointSizeF())
# painter.setFont(font)
# painter.setPen(QtCore.Qt.black)
# painter.drawText(0, 0, r.width() / 2, r.height()-1, QtCore.Qt.AlignCenter, "Brightfield")
# painter.drawText( r.width() / 2, 0, r.width() / 2, r.height() - 1, QtCore.Qt.AlignCenter, "Darkfield")
#
# def updateSliderRect(self, size):
# self._sliderShape.setWidth(size.width() / 2.0)
# self._sliderShape.setHeight(size.height() - 1.0)
#
# @QtCore.pyqtSlot(bool, name='animate')
# def animate(self, checked):
# self.animation.setDirection(QtCore.QPropertyAnimation.Forward if checked else QtCore.QPropertyAnimation.Backward)
# self.animation.start()
#
#
#class QSlideSwitch(QtWidgets.QAbstractButton):
# def __init__(self, parent = None):
# super(QSlideSwitch, self).__init__(parent)
#
# self.d_ptr = QSlideSwitchPrivate( self )
# self.clicked.connect( self.d_ptr.animate )
# self.d_ptr.animation.finished.connect( self.update )
#
# def __del__(self):
# del self.d_ptr
#
# def sizeHint(self):
# return QtCore.QSize(48, 28)
#
# def hitButton(self, point):
# return self.rect().contains(point)
#
# def paintEvent(self, event):
# painter = QtGui.QPainter(self)
# painter.setRenderHint(QtGui.QPainter.Antialiasing)
# self.d_ptr.drawSlider(painter)
#
# def resizeEvent(self, event):
# self.d_ptr.updateSliderRect(event.size())
# self.repaint()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
win = RamanSwitch()
win.show()
sys.exit(app.exec_())
\ No newline at end of file
...@@ -44,7 +44,7 @@ class RamanBase(object): ...@@ -44,7 +44,7 @@ class RamanBase(object):
def getUserZ(self): def getUserZ(self):
raise NotImplementedError raise NotImplementedError
def moveToAbsolutePosition(self, x, y, z=None, epsxy=0.11, epsz=0.011): def moveToAbsolutePosition(self, x, y, z=None, epsxy=0.11, epsz=0.011, debugReturn=False, measurementRunning=False):
raise NotImplementedError raise NotImplementedError
def moveZto(self, z, epsz=0.011): def moveZto(self, z, epsz=0.011):
...@@ -53,7 +53,7 @@ class RamanBase(object): ...@@ -53,7 +53,7 @@ class RamanBase(object):
def saveImage(self, fname): def saveImage(self, fname):
raise NotImplementedError raise NotImplementedError
def getImageDimensions(self): def getImageDimensions(self, mode = 'df'):
""" Get the image width and height in um and the orientation angle in degrees. """ Get the image width and height in um and the orientation angle in degrees.
""" """
raise NotImplementedError raise NotImplementedError
...@@ -61,8 +61,11 @@ class RamanBase(object): ...@@ -61,8 +61,11 @@ class RamanBase(object):
def startSinglePointScan(self): def startSinglePointScan(self):
raise NotImplementedError raise NotImplementedError
def initiateTimeSeriesScan(self, label, numberofscans, accumulations, integrtime): def initiateMeasurement(self, ramanSettings):
raise NotImplementedError raise NotImplementedError
def nextTimeSeriesScan(self, num): def triggerMeasurement(self, num):
raise NotImplementedError
def finishMeasurement(self):
raise NotImplementedError raise NotImplementedError
\ No newline at end of file
...@@ -23,12 +23,14 @@ import configparser ...@@ -23,12 +23,14 @@ import configparser
__all__ = ["RamanControl", "defaultPath", "simulatedRaman"] __all__ = ["RamanControl", "defaultPath", "simulatedRaman"]
defaultPath = os.path.split(__file__)[0]
defaultPath = os.path.dirname(os.path.split(__file__)[0])
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read(os.path.join(defaultPath, 'gepard.cfg')) config.read(os.path.join(defaultPath, 'gepard.cfg'))
interface = "SIMULATED_RAMAN_CONTROL" interface = "RENISHAW_CONTROL"
try: try:
defaultPath = config["Defaults"]["file_path"] defaultPath = config["Defaults"]["file_path"]
...@@ -41,15 +43,33 @@ except KeyError: ...@@ -41,15 +43,33 @@ except KeyError:
pass pass
if interface == "SIMULATED_RAMAN_CONTROL": if interface == "SIMULATED_RAMAN_CONTROL":
from simulatedraman import SimulatedRaman from ramancom.simulatedraman import SimulatedRaman
RamanControl = SimulatedRaman RamanControl = SimulatedRaman
print("WARNING: using only simulated raman control!") print("WARNING: using only simulated raman control!")
simulatedRaman = True simulatedRaman = True
elif interface == "WITEC_CONTROL": elif interface == "WITEC_CONTROL":
from WITecCOM import WITecCOM from ramancom.WITecCOM import WITecCOM
RamanControl = WITecCOM RamanControl = WITecCOM
RamanControl.magn = int(config["General Microscope Setup"]["magnification"]) # not yet implemented in WITecCOM, but would probably be a good idea...
simulatedRaman = False simulatedRaman = False
elif interface == "RENISHAW_CONTROL": elif interface == "RENISHAW_CONTROL":
raise NotImplementedError from ramancom.renishawcom import RenishawCOM
RamanControl = RenishawCOM
RamanControl.magn = int(config["General Microscope Setup"]["magnification"])
try:
bf_dims = config["Renishaw"]["img_size_BF"].split('*')
df_dims = config["Renishaw"]["img_size_DF"].split('*')
RamanControl.cam_bf_dims = [float(bf_dims[0]), float(bf_dims[1])]
RamanControl.cam_df_dims = [float(df_dims[0]), float(df_dims[1])]
except:
print('Invalid image dimensions in config file!')
# RamanControl.defaultMeasTemplate = config["Renishaw"]["defaultMeasTemplate"]
RamanControl.measTemplatePath = config["Renishaw"]["measTemplatePath"]
print(RamanControl.measTemplatePath)
RamanControl.ramanParameters = RamanControl.updateRamanParameters(RamanControl, RamanControl.measTemplatePath)