...
 
Commits (4)
......@@ -220,9 +220,11 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.layout.addLayout(self.menuLayout)
self.layout.addLayout(viewLayout)
if self.datastats.config['minHQI'] is not None:
self.hqiSpinBox.setValue(self.datastats.config['minHQI'])
self.compHqiSpinBox.setValue(self.datastats.config['compHQI'])
minHQI = self.datastats.dataset.resultParams['minHQI']
compHQI = self.datastats.dataset.resultParams['compHQI']
if minHQI is not None:
self.hqiSpinBox.setValue(minHQI)
self.compHqiSpinBox.setValue(compHQI)
self.createActions()
self.createMenus()
......@@ -399,7 +401,8 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.resultCheckBoxesLayout.addWidget(self.showTotalSelector)
#generate new checkboxes
self.polymerCheckBoxes = []
for index, polymer in enumerate(self.datastats.uniquePolymers):
uniquePolymers = self.datastats.getUniquePolymers()
for index, polymer in enumerate(uniquePolymers):
self.polymerCheckBoxes.append(QtWidgets.QCheckBox(self))
self.polymerCheckBoxes[index].setText(polymer)
self.resultCheckBoxesLayout.addWidget(self.polymerCheckBoxes[index])
......@@ -427,7 +430,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.navigationGroup.setEnabled(True)
self.polymerComboBox.currentIndexChanged.disconnect()
self.polymerComboBox.clear()
self.polymerComboBox.addItems(self.datastats.uniquePolymers)
self.polymerComboBox.addItems(uniquePolymers)
self.polymerComboBox.currentIndexChanged.connect(self.displayNewPolymerType)
self.polymerIndex = self.polymerComboBox.currentIndex()
......@@ -453,6 +456,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
#draw Sample Spectrum
specIndex = self.currentSpectrumIndex
spectra = self.datastats.spectra
particlestats = self.datastats.getParticleStats()
self.spec_ax.axis("on")
self.spec_ax.clear()
self.spec_ax.plot(spectra[:, 0], spectra[:, specIndex+1])
......@@ -460,7 +464,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.spec_ax.set_xlabel('Wavenumber (cm-1)', fontsize = 15)
self.spec_ax.set_ylabel('Counts', fontsize = 15)
self.spec_ax.set_title('ScanPoint Number {}, Size = {} µm'.format(specIndex+1,
np.round(self.datastats.particlestats[self.currentParticleIndex][2], 1)))
np.round(particlestats[self.currentParticleIndex][2], 1)))
self.spec_ax.set_xbound(100, (3400 if spectra[-1, 0] > 3400 else spectra[-1, 0]))
wavenumber_diff = list(spectra[:, 0]-100)
y_start = wavenumber_diff.index(min(wavenumber_diff))
......@@ -489,6 +493,48 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.parent.centerOnRamanIndex(specIndex, centerOn=centerOn, highlightContour=highlightContour)
self.parent.highLightRamanIndex(specIndex)
self.lastSpectrumInFocus = specIndex
def selectContour(self, index, centerOn=True):
uniquePolymers = self.datastats.getUniquePolymers()
if uniquePolymers is not None:
#the index is the contour index, find particle index:
specIndex = self.datastats.particles2spectra[index][0] #select first spectrum of partoicle
self.currentParticleIndex = index
self.currentSpectrumIndex = specIndex
selectedPolymer = self.datastats.currentPolymers[specIndex]
try:
self.polymerIndex = uniquePolymers.index(selectedPolymer)
except:
print(selectedPolymer)
raise
#subparticleIndex
partIndicesOfThatPolymer = self.datastats.indices[self.polymerIndex]
subPartInd = partIndicesOfThatPolymer.index(index)
#disconnect analysis widgets:
self.particleSelector.valueChanged.disconnect()
self.spectrumSelector.valueChanged.disconnect()
self.polymerComboBox.currentIndexChanged.disconnect()
#set widgets...
self.particleSelector.setValue(subPartInd+1)
self.particleSelector.setMaximum(len(partIndicesOfThatPolymer))
self.spectrumSelector.setValue(1)
self.spectrumSelector.setMaximum(len(self.datastats.particles2spectra[index]))
selectedPolymer = self.datastats.currentPolymers[specIndex]
self.polymerIndex = uniquePolymers.index(selectedPolymer)
self.polymerComboBox.setCurrentIndex(self.polymerIndex)
#reconnect all widgets:
self.particleSelector.valueChanged.connect(self.selectParticle)
self.spectrumSelector.valueChanged.connect(self.selectSpectrum)
self.polymerComboBox.currentIndexChanged.connect(self.displayNewPolymerType)
self.updateSpecPlot(centerOn=centerOn)
def displayNewPolymerType(self, resetCurrentIndex=True):
self.polymerIndex = self.polymerComboBox.currentIndex()
......@@ -604,7 +650,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
#general size histogram
self.bins = np.logspace(0.1, 3, 20)
self.sizes = [i[0] if np.isnan(i[2]) else i[2] for i in self.datastats.particlestats] #extract long size (if ellipse fit is nan -> box fit)
self.sizes = [i[0] if np.isnan(i[2]) else i[2] for i in self.datastats.getParticleStats()] #extract long size (if ellipse fit is nan -> box fit)
sizehist = np.histogram(self.sizes, self.bins)
self.totalhistx = []
for i in range(19):
......@@ -676,6 +722,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
return color
def createPolymerOverlay(self):
uniquePolymers = self.datastats.getUniquePolymers()
if not self.noOverlayAct.isChecked() and self.datastats.indices is not None:
if len(self.datastats.indices) > 0:
......@@ -686,9 +733,9 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
for index, indexList in enumerate(self.datastats.indices):
if self.fullOverlayAct.isChecked() or (self.selOverlayAct.isChecked() and self.polymerCheckBoxes[index].isChecked()):
color = self.getColorFromName(self.datastats.uniquePolymers[index], base255=True)
color = self.getColorFromName(uniquePolymers[index], base255=True)
color = QtGui.QColor(color[0], color[1], color[2], alpha=alpha)
legendItems.append((self.datastats.uniquePolymers[index], color))
legendItems.append((uniquePolymers[index], color))
for i in indexList:
colorList[i] = color
......
......@@ -36,7 +36,7 @@ class ExpExcelDialog(QtWidgets.QDialog):
self.setGeometry(200,200, 300, 300)
self.datastats = datastats
self.particles = self.datastats.particlestats
self.particles = self.datastats.getParticleStats()
self.polymers = self.datastats.particleResults
self.additives = self.datastats.currentAdditives
self.hqis = self.datastats.hqis
......
......@@ -21,20 +21,30 @@ If not, see <https://www.gnu.org/licenses/>.
import os
import numpy as np
import operator
from dataset import loadData, recursiveDictCompare
def readDataStats(fname):
ds = loadData(fname)
datastats = DataStats(ds)
datastats.update()
datastats.loadParticleData()
minHQI = datastats.dataset.resultParams['minHQI']
compHQI = datastats.dataset.resultParams['compHQI']
datastats.formatResults(minHQI, compHQI)
datastats.createHistogramData()
return datastats
class DataStats(object):
def __init__(self, dataset):
self.dataset = dataset
self.config = dataset.resultParams
self.spectraResults = None #entire List of all spectra assignments
self.additiveResults = None #entire List of all additives
self.particlestats = None
self.particleResults = None #final assignment for each particle
self.currentPolymers = None #list of polymers after setting entries with low hqi to unknown
self.currentAdditives = None #same thing for the additives
self.uniquePolymers = None #list of present polymer types
self.spectra = None #acquired spectra
self.indices = None #assignment of what spectra-indices belong to what substance
......@@ -102,15 +112,6 @@ class DataStats(object):
return specs
def loadParticleData(self):
self.particlestats = np.array(self.dataset.particlestats)
pixelscale = (self.dataset.pixelscale_df if self.dataset.imagescanMode == 'df' else self.dataset.pixelscale_bf)
#convert to mikrometer scale
for index in range(len(self.particlestats)):
for subindex in range(5):
self.particlestats[index][subindex] = self.particlestats[index][subindex] * pixelscale #multiply by pixelscale
if subindex == 4:
self.particlestats[index][subindex] = self.particlestats[index][subindex] * pixelscale #again for the area...
self.particles2spectra = self.dataset.particles2spectra
sortindices = self.dataset.ramanscansortindex
......@@ -145,12 +146,26 @@ class DataStats(object):
if self.currentAdditives is not None:
self.currentAdditives[self.addhqis < compHqi] = 'unknown'
def getUniquePolymers(self):
if self.currentPolymers is None:
return None
return self.uniquePolymers
def getParticleStats(self):
particlestats = np.array(self.dataset.particlestats)
pixelscale = self.dataset.getPixelScale()
#convert to mikrometer scale
particlestats[:,:5] *= pixelscale
particlestats[:,4] *= pixelscale #again for the area...
return particlestats
def createHistogramData(self):
particlestats = self.getParticleStats()
self.uniquePolymers = np.unique(self.currentPolymers)
self.particleResults = [None]*len(self.particlestats)
self.particleResults = [None]*len(particlestats)
self.typehistogram = {i: 0 for i in self.uniquePolymers}
if len(self.particles2spectra) != len(self.particlestats):
if len(self.particles2spectra) != len(particlestats):
return False
for particleID, specList in enumerate(self.particles2spectra):
......@@ -192,4 +207,12 @@ class DataStats(object):
self.dataset.resultParams = {'minHQI': minHQI,
'compHQI': compHQI}
self.dataset.save()
print('saved dataset')
\ No newline at end of file
testresult = self.testRead()
print('saved dataset; Valid:', testresult)
return testresult
def testRead(self):
statsread = readDataStats(self.dataset.fname)
return recursiveDictCompare(self.__dict__, statsread.__dict__)
\ No newline at end of file
......@@ -261,7 +261,12 @@ class LoadWITecResults(QtWidgets.QDialog):
self.parent.updateBtn.clicked.connect(self.parent.formatResults)
self.parent.formatResults()
self.parent.show_hide_labels()
self.parent.saveAnalysisResults()
minHQI = self.parent.hqiSpinBox.value()
compHQI = self.parent.compHqiSpinBox.value()
if not self.parent.datastats.saveAnalysisResults(minHQI, compHQI):
QtWidgets.QMessageBox.warning(self.parent, 'Error!',
'Data inconsistency after saving!',
QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
self.parent.setEnabled(True)
event.accept()
......
......@@ -24,6 +24,7 @@ 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
......@@ -56,8 +57,6 @@ class ParticleEditor(object):
return
contourIndices = sorted(contourIndices) #we want to keep the contour with lowest index
print('merging contours:', contourIndices)
self.createSafetyBackup()
#get contours:
contours = [self.datastats.dataset.particlecontours[i] for i in contourIndices]
cnt = np.vstack(tuple(contours)) #combine contous
......@@ -72,7 +71,7 @@ class ParticleEditor(object):
img = np.zeros((rangey, rangex))
for i in contourIndices:
curCnt = self.datastats.dataset.particlecontours[i]
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
......@@ -87,6 +86,11 @@ class ParticleEditor(object):
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)
......@@ -94,6 +98,8 @@ class ParticleEditor(object):
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
......@@ -133,12 +139,17 @@ class ParticleEditor(object):
print('removing index from particles2spectra:', index)
del self.datastats.dataset.particles2spectra[index]
#save data
self.datastats.saveAnalysisResults()
#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):
......@@ -155,10 +166,16 @@ class ParticleEditor(object):
self.datastats.spectraResults[specIndex] = new_assignment
self.datastats.hqis[specIndex] = 100
#save data
self.datastats.saveAnalysisResults()
#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):
......
......@@ -21,16 +21,16 @@ class SQLExport(QtWidgets.QDialog):
self.datastats = datastats
self.polymerList = self.datastats.particleResults
self.longSizes = np.round(np.array([i[0] if np.isnan(i[2]) else i[2] for i in self.datastats.particlestats]), 1)
self.shortSize = np.round(np.array([i[1] if np.isnan(i[3]) else i[3] for i in self.datastats.particlestats]), 1)
particlestats = self.datastats.getParticleStats()
self.longSizes = np.round(np.array([i[0] if np.isnan(i[2]) else i[2] for i in particlestats]), 1)
self.shortSize = np.round(np.array([i[1] if np.isnan(i[3]) else i[3] for i in particlestats]), 1)
#spectra can be quite some data size, they are not copied here but referenced later on...
self.particleImages = None
self.log = []
configfilename = os.path.join(os.path.dirname(os.path.split(__file__)[0]),
'database_config.txt')
configfilename = os.path.join(os.path.split(__file__)[0], 'database_config.txt')
if not os.path.exists(configfilename):
QtWidgets.QMessageBox.warning(self, 'Warning!',
......@@ -338,6 +338,9 @@ class SQLExport(QtWidgets.QDialog):
self.cnx = mysql.connector.connect(**self.config) #port: 3306
except mysql.connector.Error as err:
print(err)
QtWidgets.QMessageBox.warning(self, 'Error!',
str(err),
QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
self.cnx = None
def getEntireTable(self, tablename):
......
......@@ -53,6 +53,58 @@ def saveData(dataset, fname):
pickle.dump(dataset, fp, protocol=-1)
dataset.zvalimg = zvalimg
def arrayCompare(a1, a2):
if a1.shape!=a2.shape:
return False
if a1.dtype!=np.float32 and a1.dtype!=np.float64:
return np.all(a1==a2)
ind = np.isnan(a1)
if not np.any(ind):
return np.all(a1==a2)
return np.all(a1[~ind]==a2[~ind])
def listCompare(l1, l2):
if len(l1)!=len(l2):
return False
for l1i, l2i in zip(l1, l2):
if isinstance(l1i, np.ndarray):
if not isinstance(l2i, np.ndarray) or not arrayCompare(l1i, l2i):
return False
elif isinstance(l1i, (list, tuple)):
if not isinstance(l2i, (list, tuple)) or not listCompare(l1i, l2i):
return False
elif l1i!=l2i and ((~np.isnan(l1i)) or (~np.isnan(l2i))):
return False
return True
def recursiveDictCompare(d1, d2):
for key in d1:
if not key in d2:
print("key missing in d2:", key, flush=True)
return False
a = d1[key]
b = d2[key]
print(key, type(a), type(b), flush=True)
if isinstance(a, np.ndarray):
if not isinstance(b, np.ndarray) or not arrayCompare(a, b):
print("data is different!", a, b)
return False
elif isinstance(a, dict):
if not isinstance(b, dict):
print("data is different!", a, b)
return False
if not recursiveDictCompare(a, b):
return False
elif isinstance(a, (list, tuple)):
if not isinstance(b, (list, tuple)) or not listCompare(a, b):
print("data is different!", a, b)
return False
elif a != b:
if (a is not None) and (b is not None):
print("data is different!", a, b)
return False
return True
class DataSet(object):
def __init__(self, fname, newProject=False):
self.fname = fname
......@@ -115,6 +167,14 @@ class DataSet(object):
self.fname = self.newProject(fname)
self.updatePath()
def __eq__(self, other):
return recursiveDictCompare(self.__dict__, other.__dict__)
def getPixelScale(self, mode=None):
if mode is None:
mode = self.imagescanMode
return (self.pixelscale_df if mode == 'df' else self.pixelscale_bf)
def saveZvalImg(self):
if self.zvalimg is not None:
cv2imwrite_fix(self.getZvalImageName(), self.zvalimg)
......@@ -243,8 +303,7 @@ class DataSet(object):
p0[1] += self.imagedim_bf[1]/2
return (pixelpos[0]*self.pixelscale_bf + p0[0]), (p0[1] - pixelpos[1]*self.pixelscale_bf)
else:
print('mapToRamanMode not understood')
return
raise ValueError(f'mapToLength mode: {mode} not understood')
def mapToLengthRaman(self, pixelpos, microscopeMode='df', noz=False):
p0x, p0y = self.mapToLength(pixelpos, mode = microscopeMode)
......@@ -315,9 +374,7 @@ class DataSet(object):
saveData(self, self.fname)
def saveBackup(self):
# backupNameNotFound = True
inc = 0
# while backupNameNotFound:
while True:
directory = os.path.dirname(self.fname)
filename = self.name + '_backup_' + str(inc) + '.pkl'
......@@ -327,5 +384,4 @@ class DataSet(object):
else:
saveData(self, path)
return filename
# backupNameNotFound = False
# -*- 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, QtGui, QtWidgets
import numpy as np
import os
from dataset import DataSet, loadData
from ramancom.ramancontrol import RamanControl, simulatedRaman
from opticalscan import OpticalScan
from ramanscanui import RamanScanUI
from detectionview import ParticleDetectionView
from analysis.analysisview import ParticleAnalysis
from zeissimporter import ZeissImporter
from viewitems import FitPosIndicator, Node, Edge, ScanIndicator, RamanScanIndicator, SegmentationContours
from helperfunctions import polygoncovering, cv2imread_fix
import cv2
from ramancom.configRaman import RamanConfigWin
class SampleView(QtWidgets.QGraphicsView):
ScalingChanged = QtCore.pyqtSignal(float)
def __init__(self, logpath):
super(SampleView, self).__init__()
self.logpath = logpath
self.item = QtWidgets.QGraphicsPixmapItem()
self.item.setPos(0, 0)
self.item.setAcceptedMouseButtons(QtCore.Qt.NoButton)
self.scaleFactor = 1.0
scene = QtWidgets.QGraphicsScene(self)
scene.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex)
scene.addItem(self.item)
scene.setBackgroundBrush(QtCore.Qt.darkGray)
self.setScene(scene)
self.setCacheMode(QtWidgets.QGraphicsView.CacheBackground)
self.setViewportUpdateMode(QtWidgets.QGraphicsView.BoundingRectViewportUpdate)
self.setRenderHint(QtGui.QPainter.Antialiasing)
self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorViewCenter)
self.ramanctrl = RamanControl()
self.simulatedRaman = simulatedRaman
#determine, if ramanSwitch is needed:
self.ramanctrl.connect()
if not self.ramanctrl.connected:
QtWidgets.QMessageBox.warning(self, 'Error', 'Please enable Raman Connection')
return
if self.ramanctrl.getImageDimensions(mode='bf')[0] == self.ramanctrl.getImageDimensions(mode='df')[0]:
self.ramanSwitchNeeded = False
else:
self.ramanSwitchNeeded = True
self.ramanctrl.disconnect()
self.drag = None
self.mode = None
self.dataset = None
self.fititems = []
self.boundaryitems = [[],[]]
self.scanitems = []
self.ramanscanitems = []
self.imgdata = None
self.isblocked = False
self.contouritem = SegmentationContours(self)
scene.addItem(self.contouritem)
self.detectionwidget = None
self.ramanwidget = RamanScanUI(self.ramanctrl, None, self.logpath, self)
self.ramanwidget.imageUpdate.connect(self.loadPixmap)
self.oscanwidget = OpticalScan(self.ramanctrl, None, self.logpath, self)
self.oscanwidget.imageUpdate.connect(self.loadPixmap)
self.oscanwidget.boundaryUpdate.connect(self.resetBoundary)
self.analysiswidget = None
self.setMinimumSize(600, 600)
self.darkenPixmap = False
self.microscopeMode = None
self.coordTestMode = False
def takeScreenshot(self):
#TODO:
#LIMIT SCREENSHOT TO ACTUAL VIEWSIZE OF LOADED IMAGE...
#hide scrollbars
self.setHorizontalScrollBarPolicy(1)
self.setVerticalScrollBarPolicy(1)
#capture screen
screen = QtWidgets.QApplication.primaryScreen()
self.repaint()
screenshot = screen.grabWindow(self.winId())
#unhide scrollbars
self.setHorizontalScrollBarPolicy(0)
self.setVerticalScrollBarPolicy(0)
fname = self.dataset.path + '/screenshot.png'
validFileName = False
incr = 1
while not validFileName:
if not os.path.exists(fname):
validFileName = True
else:
fname = self.dataset.path + '/screenshot ({}).png'.format(incr)
incr += 1
screenshot.save(fname , 'png')
QtWidgets.QMessageBox.about(self, 'Message', 'Saved as {} to project directory.'.format(fname.split('/')[-1]))
def closeEvent(self, event):
reply = QtWidgets.QMessageBox.question(self, 'Message',
"Are you sure to quit?", QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
self.disconnectRaman()
self.saveDataSet()
event.accept()
self.oscanwidget.close()
if self.detectionwidget is not None:
self.detectionwidget.close()
if self.analysiswidget is not None:
self.analysiswidget.close()
self.ramanwidget.close()
else:
event.ignore()
def configureRamanControl(self):
self.configWin = RamanConfigWin(self)
self.configWin.show()
def saveDataSet(self):
if self.dataset is not None:
self.dataset.save()
@QtCore.pyqtSlot()
def zoomIn(self):
self.scaleImage(1.25)
@QtCore.pyqtSlot()
def zoomOut(self):
self.scaleImage(0.8)
@QtCore.pyqtSlot()
def normalSize(self):
self.scaleFactor = 1.0
self.setTransform(QtGui.QTransform.fromScale(1., 1.))
self.announceScaling()
@QtCore.pyqtSlot()
def fitToWindow(self):
# print("fitting to Window")
brect = self.item.sceneBoundingRect()
self.fitInView(0, 0, brect.width(), brect.height(), QtCore.Qt.KeepAspectRatio)
self.scaleFactor = self.transform().m11()
self.announceScaling()
def switchMode(self, mode, loadnew=False):
if mode is None:
return
assert mode in ["OpticalScan", "ParticleDetection", "RamanScan", "ParticleAnalysis"]
self.oscanwidget.setVisible(False)
if self.detectionwidget is not None:
self.detectionwidget.close()
self.detectionwidget.destroy()
self.ramanwidget.setVisible(False)
self.contouritem.resetContours([])
self.mode = mode
self.loadPixmap(self.microscopeMode)
if mode == "OpticalScan":
self.oscanwidget.setVisible(True)
self.oscanwidget.resetDataset(self.dataset)
elif mode == "ParticleDetection":
if self.detectionwidget is None:
self.detectionwidget = ParticleDetectionView(self.imgdata, self.dataset, self)
self.detectionwidget.show()
self.detectionwidget.imageUpdate.connect(self.detectionUpdate)
self.detectionwidget.detectionFinished.connect(self.activateMaxMode)
elif mode == "RamanScan":
self.ramanwidget.resetDataset(self.dataset)
self.ramanwidget.setVisible(True)
elif mode == "ParticleAnalysis":
if self.ramanwidget.isVisible():
self.ramanwidget.setVisible(False)
if self.analysiswidget is None:
print('creating new analysiswidget')
self.analysiswidget = ParticleAnalysis(self.dataset, self)
self.analysiswidget.showMaximized()
else:
print('show maximized already exisiting analysiswidget')
self.analysiswidget.showMaximized()
# self.ramanwidget.setVisible(False)
if self.detectionwidget is not None:
self.detectionwidget.setVisible(False)
#show legend:
self.imparent.legend.show()
if loadnew:
self.fitToWindow()
self.imparent.updateModes(mode, self.getMaxMode())
def open(self, fname):
self.saveDataSet()
#close all widgets
for widget in [self.detectionwidget, self.ramanwidget, self.oscanwidget, self.analysiswidget]:
if widget is not None:
widget.close()
widget.destroy()
del widget
self.contouritem.resetContours()
# if self.dataset is not None:
# del self.dataset
# self.scene().removeItem(self.contouritem)
# del self.contouritem
# self.contouritem = SegmentationContours(self)
# self.scene().addItem(self.contouritem)
self.dataset = loadData(fname)
self.setMicroscopeMode()
self.imparent.setWindowTitle(self.dataset.name + (" SIMULATION" if simulatedRaman else ""))
self.imgdata = None
self.activateMaxMode(loadnew=True)
self.imparent.snapshotAct.setEnabled(True)
def importProject(self, fname):
zimp = ZeissImporter(fname, self.ramanctrl, self)
if zimp.validimport:
zimp.exec()
if zimp.result() == QtWidgets.QDialog.Accepted:
self.open(zimp.gepardname)
def new(self, fname):
self.saveDataSet()
if self.dataset is not None:
self.dataset.save()
self.dataset = DataSet(fname, newProject=True)
self.setMicroscopeMode()
self.imparent.setWindowTitle(self.dataset.name + (" SIMULATION" if simulatedRaman else ""))
self.imgdata = None
self.activateMaxMode(loadnew=True)
self.imparent.snapshotAct.setEnabled(True)
def setMicroscopeMode(self):
if self.ramanSwitchNeeded:
self.imparent.ramanSwitch.connectToSampleView()
self.imparent.ramanSwitch.show()
self.microscopeMode = ('df' if self.imparent.ramanSwitch.df_btn.isChecked() else 'bf')
@QtCore.pyqtSlot()
def activateMaxMode(self, loadnew=False):
mode = self.getMaxMode()
self.imparent.updateModes(self.mode, self.getMaxMode())
self.switchMode(mode, loadnew=loadnew)
def blockUI(self):
self.isblocked = True
self.imparent.blockUI()
def unblockUI(self):
self.isblocked = False
self.imparent.unblockUI(self.ramanctrl.connected)
self.imparent.updateModes(self.mode, self.getMaxMode())
def getMaxMode(self):
if self.dataset is None:
return None
if not self.ramanctrl.connected:
self.connectRaman()
if not self.ramanctrl.connected:
return None
maxmode = "OpticalScan"
if os.path.exists(self.dataset.getImageName()):
maxmode = "ParticleDetection"
if len(self.dataset.ramanpoints)>0:
maxmode = "RamanScan"
if self.dataset.ramanscandone: #uncomment!!
maxmode = "ParticleAnalysis"
return maxmode
def mousePressEvent(self, event):
# if event.button()==QtCore.Qt.RightButton:
if event.button()==QtCore.Qt.MiddleButton:
self.drag = event.pos()
elif event.button()==QtCore.Qt.LeftButton and self.mode in ["OpticalScan", "RamanScan"] \
and event.modifiers()==QtCore.Qt.ControlModifier:
p0 = self.mapToScene(event.pos())
if self.dataset is not None and self.dataset.pshift is not None:
if self.dataset.readin:
reply = QtWidgets.QMessageBox.critical(self, 'Dataset is newly read from disk!',
"Coordinate systems might have changed since. Do you want to continue with saved coordinates?",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
self.dataset.readin = False
else:
return
x, y, z = self.dataset.mapToLengthRaman([p0.x(), p0.y()],
microscopeMode=self.microscopeMode,
noz=(False if self.mode=="RamanScan" else True))
if z is not None:
assert z>-100.
self.ramanctrl.moveToAbsolutePosition(x, y, z)
elif event.button()==QtCore.Qt.LeftButton and self.mode=="ParticleDetection":
p0 = self.mapToScene(event.pos())
self.detectionwidget.setImageCenter([p0.x(), p0.y()])
# elif event.button()==QtCore.Qt.LeftButton and self.mode=="ParticleAnalysis":
# p0 = self.mapToScene(event.pos())
else:
p0 = self.mapToScene(event.pos())
super(SampleView, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.drag is not None:
p0 = event.pos()
move = self.drag-p0
self.horizontalScrollBar().setValue(move.x() + self.horizontalScrollBar().value())
self.verticalScrollBar().setValue(move.y() + self.verticalScrollBar().value())
self.drag = p0
else:
super(SampleView, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.drag = None
super(SampleView, self).mouseReleaseEvent(event)
def wheelEvent(self, event):
factor = 1.01**(event.angleDelta().y()/8)
self.scaleImage(factor)
def scaleImage(self, factor):
if factor<1 and not self.imparent.zoomOutAct.isEnabled():
return
if factor>1 and not self.imparent.zoomInAct.isEnabled():
return
self.scaleFactor *= factor
self.scale(factor, factor)
self.announceScaling()
def announceScaling(self):
pixelscale = (self.dataset.pixelscale_df if self.microscopeMode == 'df' else self.dataset.pixelscale_bf)
if self.dataset is None or pixelscale is None:
self.ScalingChanged.emit(-1.0)
else:
self.ScalingChanged.emit(pixelscale/self.scaleFactor) ##CURRENTLY ONLY DARKFIELD!!! FIX NEEDED!!!
def connectRaman(self):
if not self.ramanctrl.connect():
msg = QtWidgets.QMessageBox()
msg.setText("Connection failed! Please enable remote control.")
msg.exec()
else:
mode = self.getMaxMode()
self.switchMode(mode)
self.imparent.updateConnected(self.ramanctrl.connected)
def disconnectRaman(self):
self.ramanctrl.disconnect()
self.imparent.updateConnected(self.ramanctrl.connected)
@QtCore.pyqtSlot(str)
def detectionUpdate(self):
self.contouritem.resetContours(self.dataset.particlecontours)
self.prepareAnalysis()
self.update()
@QtCore.pyqtSlot(str)
def loadPixmap(self, microscope_mode='df'):
self.clearItems()
if self.dataset is None:
self.item.setPixmap(QtGui.QPixmap())
else:
data = self.imgdata
fname = self.dataset.getImageName()
if self.mode == "ParticleDetection" or self.mode == "ParticleAnalysis":
self.contouritem.resetContours(self.dataset.particlecontours)
if data is None and os.path.exists(fname):
data = cv2.cvtColor(cv2imread_fix(fname), cv2.COLOR_BGR2RGB)
self.imgdata = data
if data is not None:
height, width, channel = data.shape
bytesPerLine = 3 * width
pix = QtGui.QPixmap()
pix.convertFromImage(QtGui.QImage(data.data,
width, height, bytesPerLine, QtGui.QImage.Format_RGB888))
self.item.setPixmap(pix)
if self.darkenPixmap:
self.scene().setBackgroundBrush(QtGui.QColor(5, 5, 5))
self.item.setOpacity(0.2)
else:
self.scene().setBackgroundBrush(QtCore.Qt.darkGray)
self.item.setOpacity(1)
else:
self.item.setPixmap(QtGui.QPixmap())
if self.mode == "OpticalScan":
for i, p in zip(self.dataset.fitindices, self.dataset.fitpoints):
p = self.dataset.mapToPixel(p, mode=microscope_mode, force=True)
fititem = FitPosIndicator(i+1, pos=p)
self.scene().addItem(fititem)
self.fititems.append(fititem)
if self.mode == "ParticleDetection" or self.mode == "ParticleAnalysis":
self.prepareAnalysis()
else:
self.fitToWindow()
@QtCore.pyqtSlot()
def resetScanPositions(self):
micMode = ('df' if self.oscanwidget.df_btn.isChecked() else 'bf')
for item in self.scanitems:
self.scene().removeItem(item)
edges, nodes = self.boundaryitems
boundary = []
for n in nodes:
p = n.pos().x(), n.pos().y()
boundary.append(self.dataset.mapToLength(p, self.microscopeMode, force=True))
boundary = np.array(boundary)
# print(boundary)
self.dataset.boundary = boundary
if micMode == 'df':
width, height, angle = self.dataset.imagedim_df
else:
width, height, angle = self.dataset.imagedim_bf
margin = min(width, height)*0.02
wx, wy = width-margin, height-margin
print(wx,wy)
p1 = polygoncovering(boundary, wx, wy)
b2 = boundary.copy()
b2 = b2[:,[1,0]]
p2 = polygoncovering(b2, wy, wx)
if len(p2)<len(p1):
p1 = [[pi[1],pi[0]] for pi in p2]
self.dataset.grid = p1
if self.microscopeMode == 'df':
wxs, wys = width/self.dataset.pixelscale_df, height/self.dataset.pixelscale_df
# -*- 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, QtGui, QtWidgets
import numpy as np
import os
from dataset import DataSet, loadData
from ramancom.ramancontrol import RamanControl, simulatedRaman
from opticalscan import OpticalScan
from ramanscanui import RamanScanUI
from detectionview import ParticleDetectionView
from analysis.analysisview import ParticleAnalysis
from zeissimporter import ZeissImporter
from viewitems import FitPosIndicator, Node, Edge, ScanIndicator, RamanScanIndicator, SegmentationContours
from helperfunctions import polygoncovering, cv2imread_fix
import cv2
from ramancom.configRaman import RamanConfigWin
class SampleView(QtWidgets.QGraphicsView):
ScalingChanged = QtCore.pyqtSignal(float)
def __init__(self, logpath):
super(SampleView, self).__init__()
self.logpath = logpath
self.item = QtWidgets.QGraphicsPixmapItem()
self.item.setPos(0, 0)
self.item.setAcceptedMouseButtons(QtCore.Qt.NoButton)
self.scaleFactor = 1.0
scene = QtWidgets.QGraphicsScene(self)
scene.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex)
scene.addItem(self.item)
scene.setBackgroundBrush(QtCore.Qt.darkGray)
self.setScene(scene)
self.setCacheMode(QtWidgets.QGraphicsView.CacheBackground)
self.setViewportUpdateMode(QtWidgets.QGraphicsView.BoundingRectViewportUpdate)
self.setRenderHint(QtGui.QPainter.Antialiasing)
self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorViewCenter)
self.ramanctrl = RamanControl()
self.simulatedRaman = simulatedRaman
#determine, if ramanSwitch is needed:
self.ramanctrl.connect()
if not self.ramanctrl.connected:
QtWidgets.QMessageBox.warning(self, 'Error', 'Please enable Raman Connection')
return
if self.ramanctrl.getImageDimensions(mode='bf')[0] == self.ramanctrl.getImageDimensions(mode='df')[0]:
self.ramanSwitchNeeded = False
else:
wxs, wys = width/self.dataset.pixelscale_bf, height/self.dataset.pixelscale_bf
self.scanitems = []
for i, p in enumerate(p1):
p = self.dataset.mapToPixel(p, self.microscopeMode, force=True)
s = ScanIndicator(i+1, wxs, wys, p)
self.scene().addItem(s)
self.scanitems.append(s)
@QtCore.pyqtSlot()
def resetBoundary(self):
micMode = self.microscopeMode
edges, nodes = self.boundaryitems
for item in edges:
self.scene().removeItem(item)
for item in nodes:
self.scene().removeItem(item)
edges, nodes = [], []
for p in self.dataset.boundary:
p = self.dataset.mapToPixel(p, micMode, force=True)
n = Node(p, self)
nodes.append(n)
self.scene().addItem(n)
for i in range(len(nodes)):
e = Edge(nodes[i-1], nodes[i])
edges.append(e)
self.scene().addItem(e)
self.boundaryitems = edges, nodes
self.resetScanPositions()
@QtCore.pyqtSlot(int, bool)
def selectContour(self, index, centerOn=True):
if self.analysiswidget is not None:
if self.analysiswidget.uniquePolymers is not None:
#the index is the contour index, find particle index:
specIndex = self.analysiswidget.particles2spectra[index][0] #select first spectrum of partoicle
self.analysiswidget.currentParticleIndex = index
self.analysiswidget.currentSpectrumIndex = specIndex
self.ramanSwitchNeeded = True
self.ramanctrl.disconnect()
self.drag = None
self.mode = None
self.dataset = None
self.fititems = []
self.boundaryitems = [[],[]]
self.scanitems = []
self.ramanscanitems = []
self.imgdata = None
self.isblocked = False
self.contouritem = SegmentationContours(self)
scene.addItem(self.contouritem)
self.detectionwidget = None
self.ramanwidget = RamanScanUI(self.ramanctrl, None, self.logpath, self)
self.ramanwidget.imageUpdate.connect(self.loadPixmap)
self.oscanwidget = OpticalScan(self.ramanctrl, None, self.logpath, self)
self.oscanwidget.imageUpdate.connect(self.loadPixmap)
self.oscanwidget.boundaryUpdate.connect(self.resetBoundary)
self.analysiswidget = None
self.setMinimumSize(600, 600)
self.darkenPixmap = False
self.microscopeMode = None
self.coordTestMode = False
def takeScreenshot(self):
#TODO:
#LIMIT SCREENSHOT TO ACTUAL VIEWSIZE OF LOADED IMAGE...
#hide scrollbars
self.setHorizontalScrollBarPolicy(1)
self.setVerticalScrollBarPolicy(1)
#capture screen
screen = QtWidgets.QApplication.primaryScreen()
self.repaint()
screenshot = screen.grabWindow(self.winId())
#unhide scrollbars
self.setHorizontalScrollBarPolicy(0)
self.setVerticalScrollBarPolicy(0)
fname = self.dataset.path + '/screenshot.png'
validFileName = False
incr = 1
while not validFileName:
if not os.path.exists(fname):
validFileName = True
else:
fname = self.dataset.path + '/screenshot ({}).png'.format(incr)
incr += 1
screenshot.save(fname , 'png')
QtWidgets.QMessageBox.about(self, 'Message', 'Saved as {} to project directory.'.format(fname.split('/')[-1]))
def closeEvent(self, event):
reply = QtWidgets.QMessageBox.question(self, 'Message',
"Are you sure to quit?", QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
self.disconnectRaman()
self.saveDataSet()
event.accept()
self.oscanwidget.close()
if self.detectionwidget is not None:
self.detectionwidget.close()
if self.analysiswidget is not None:
self.analysiswidget.close()
self.ramanwidget.close()
else:
event.ignore()
def configureRamanControl(self):
self.configWin = RamanConfigWin(self)
self.configWin.show()
def saveDataSet(self):
if self.dataset is not None:
self.dataset.save()
@QtCore.pyqtSlot()
def zoomIn(self):
self.scaleImage(1.25)
@QtCore.pyqtSlot()
def zoomOut(self):
self.scaleImage(0.8)
@QtCore.pyqtSlot()
def normalSize(self):
self.scaleFactor = 1.0
self.setTransform(QtGui.QTransform.fromScale(1., 1.))
self.announceScaling()
@QtCore.pyqtSlot()
def fitToWindow(self):
# print("fitting to Window")
brect = self.item.sceneBoundingRect()
self.fitInView(0, 0, brect.width(), brect.height(), QtCore.Qt.KeepAspectRatio)
self.scaleFactor = self.transform().m11()
self.announceScaling()
def switchMode(self, mode, loadnew=False):
if mode is None:
return
assert mode in ["OpticalScan", "ParticleDetection", "RamanScan", "ParticleAnalysis"]
self.oscanwidget.setVisible(False)
if self.detectionwidget is not None:
self.detectionwidget.close()
self.detectionwidget.destroy()
self.ramanwidget.setVisible(False)
self.contouritem.resetContours([])
self.mode = mode
self.loadPixmap(self.microscopeMode)
if mode == "OpticalScan":
self.oscanwidget.setVisible(True)
self.oscanwidget.resetDataset(self.dataset)
elif mode == "ParticleDetection":
if self.detectionwidget is None:
self.detectionwidget = ParticleDetectionView(self.imgdata, self.dataset, self)
self.detectionwidget.show()
self.detectionwidget.imageUpdate.connect(self.detectionUpdate)
self.detectionwidget.detectionFinished.connect(self.activateMaxMode)
elif mode == "RamanScan":
self.ramanwidget.resetDataset(self.dataset)
self.ramanwidget.setVisible(True)
elif mode == "ParticleAnalysis":
if self.ramanwidget.isVisible():
self.ramanwidget.setVisible(False)
if self.analysiswidget is None:
print('creating new analysiswidget')
self.analysiswidget = ParticleAnalysis(self.dataset, self)
self.analysiswidget.showMaximized()
else:
print('show maximized already exisiting analysiswidget')
self.analysiswidget.showMaximized()
# self.ramanwidget.setVisible(False)
if self.detectionwidget is not None:
self.detectionwidget.setVisible(False)
#show legend:
self.imparent.legend.show()
if loadnew:
self.fitToWindow()
self.imparent.updateModes(mode, self.getMaxMode())
def open(self, fname):
self.saveDataSet()
#close all widgets
for widget in [self.detectionwidget, self.ramanwidget, self.oscanwidget, self.analysiswidget]:
if widget is not None:
widget.close()
widget.destroy()
del widget
selectedPolymer = self.analysiswidget.currentPolymers[specIndex]
try:
self.analysiswidget.polymerIndex = self.analysiswidget.uniquePolymers.index(selectedPolymer)
except:
print(selectedPolymer)
raise
self.contouritem.resetContours()
# if self.dataset is not None:
# del self.dataset
# self.scene().removeItem(self.contouritem)
# del self.contouritem
# self.contouritem = SegmentationContours(self)
# self.scene().addItem(self.contouritem)
self.dataset = loadData(fname)
self.setMicroscopeMode()
self.imparent.setWindowTitle(self.dataset.name + (" SIMULATION" if simulatedRaman else ""))
self.imgdata = None
self.activateMaxMode(loadnew=True)
self.imparent.snapshotAct.setEnabled(True)
def importProject(self, fname):
zimp = ZeissImporter(fname, self.ramanctrl, self)
if zimp.validimport:
zimp.exec()
if zimp.result() == QtWidgets.QDialog.Accepted:
self.open(zimp.gepardname)
def new(self, fname):
self.saveDataSet()
if self.dataset is not None:
self.dataset.save()
self.dataset = DataSet(fname, newProject=True)
self.setMicroscopeMode()
self.imparent.setWindowTitle(self.dataset.name + (" SIMULATION" if simulatedRaman else ""))
self.imgdata = None
self.activateMaxMode(loadnew=True)
self.imparent.snapshotAct.setEnabled(True)
def setMicroscopeMode(self):
if self.ramanSwitchNeeded:
self.imparent.ramanSwitch.connectToSampleView()
self.imparent.ramanSwitch.show()
self.microscopeMode = ('df' if self.imparent.ramanSwitch.df_btn.isChecked() else 'bf')
@QtCore.pyqtSlot()
def activateMaxMode(self, loadnew=False):
mode = self.getMaxMode()
self.imparent.updateModes(self.mode, self.getMaxMode())
self.switchMode(mode, loadnew=loadnew)
def blockUI(self):
self.isblocked = True
self.imparent.blockUI()
def unblockUI(self):
self.isblocked = False
self.imparent.unblockUI(self.ramanctrl.connected)
self.imparent.updateModes(self.mode, self.getMaxMode())
def getMaxMode(self):
if self.dataset is None:
return None
if not self.ramanctrl.connected:
self.connectRaman()
if not self.ramanctrl.connected:
return None
maxmode = "OpticalScan"
if os.path.exists(self.dataset.getImageName()):
maxmode = "ParticleDetection"
if len(self.dataset.ramanpoints)>0:
maxmode = "RamanScan"
if self.dataset.ramanscandone: #uncomment!!
maxmode = "ParticleAnalysis"
return maxmode
def mousePressEvent(self, event):
# if event.button()==QtCore.Qt.RightButton:
if event.button()==QtCore.Qt.MiddleButton:
self.drag = event.pos()
elif event.button()==QtCore.Qt.LeftButton and self.mode in ["OpticalScan", "RamanScan"] \
and event.modifiers()==QtCore.Qt.ControlModifier:
p0 = self.mapToScene(event.pos())
if self.dataset is not None and self.dataset.pshift is not None:
if self.dataset.readin:
reply = QtWidgets.QMessageBox.critical(self, 'Dataset is newly read from disk!',
"Coordinate systems might have changed since. Do you want to continue with saved coordinates?",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
self.dataset.readin = False
else:
return
x, y, z = self.dataset.mapToLengthRaman([p0.x(), p0.y()],
microscopeMode=self.microscopeMode,
noz=(False if self.mode=="RamanScan" else True))
if z is not None:
assert z>-100.
self.ramanctrl.moveToAbsolutePosition(x, y, z)
elif event.button()==QtCore.Qt.LeftButton and self.mode=="ParticleDetection":
p0 = self.mapToScene(event.pos())
self.detectionwidget.setImageCenter([p0.x(), p0.y()])
# elif event.button()==QtCore.Qt.LeftButton and self.mode=="ParticleAnalysis":
# p0 = self.mapToScene(event.pos())
else:
p0 = self.mapToScene(event.pos())
super(SampleView, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.drag is not None:
p0 = event.pos()
move = self.drag-p0
self.horizontalScrollBar().setValue(move.x() + self.horizontalScrollBar().value())
self.verticalScrollBar().setValue(move.y() + self.verticalScrollBar().value())
self.drag = p0
else:
super(SampleView, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.drag = None
super(SampleView, self).mouseReleaseEvent(event)
def wheelEvent(self, event):
factor = 1.01**(event.angleDelta().y()/8)
self.scaleImage(factor)
def scaleImage(self, factor):
if factor<1 and not self.imparent.zoomOutAct.isEnabled():
return
if factor>1 and not self.imparent.zoomInAct.isEnabled():
return
self.scaleFactor *= factor
self.scale(factor, factor)
self.announceScaling()
def announceScaling(self):
pixelscale = self.dataset.getPixelScale(self.microscopeMode)
if self.dataset is None or pixelscale is None:
self.ScalingChanged.emit(-1.0)
else:
self.ScalingChanged.emit(pixelscale/self.scaleFactor) ##CURRENTLY ONLY DARKFIELD!!! FIX NEEDED!!!
def connectRaman(self):
if not self.ramanctrl.connect():
msg = QtWidgets.QMessageBox()
msg.setText("Connection failed! Please enable remote control.")
msg.exec()
else:
mode = self.getMaxMode()
self.switchMode(mode)
self.imparent.updateConnected(self.ramanctrl.connected)
def disconnectRaman(self):
self.ramanctrl.disconnect()
self.imparent.updateConnected(self.ramanctrl.connected)
@QtCore.pyqtSlot(str)
def detectionUpdate(self):
self.contouritem.resetContours(self.dataset.particlecontours)
self.prepareAnalysis()
self.update()
@QtCore.pyqtSlot(str)
def loadPixmap(self, microscope_mode='df'):
self.clearItems()
if self.dataset is None:
self.item.setPixmap(QtGui.QPixmap())
else:
data = self.imgdata
fname = self.dataset.getImageName()
if self.mode == "ParticleDetection" or self.mode == "ParticleAnalysis":
self.contouritem.resetContours(self.dataset.particlecontours)
if data is None and os.path.exists(fname):
data = cv2.cvtColor(cv2imread_fix(fname), cv2.COLOR_BGR2RGB)
self.imgdata = data
if data is not None:
#subparticleIndex
partIndicesOfThatPolymer = self.analysiswidget.indices[self.analysiswidget.polymerIndex]
subPartInd = partIndicesOfThatPolymer.index(index)
height, width, channel = data.shape
bytesPerLine = 3 * width
pix = QtGui.QPixmap()
pix.convertFromImage(QtGui.QImage(data.data,
width, height, bytesPerLine, QtGui.QImage.Format_RGB888))
#disconnect analysis widgets:
self.analysiswidget.particleSelector.valueChanged.disconnect()
self.analysiswidget.spectrumSelector.valueChanged.disconnect()
self.analysiswidget.polymerComboBox.currentIndexChanged.disconnect()
self.item.setPixmap(pix)
#set widgets...
self.analysiswidget.particleSelector.setValue(subPartInd+1)
self.analysiswidget.particleSelector.setMaximum(len(partIndicesOfThatPolymer))
if self.darkenPixmap:
self.scene().setBackgroundBrush(QtGui.QColor(5, 5, 5))
self.item.setOpacity(0.2)
else:
self.scene().setBackgroundBrush(QtCore.Qt.darkGray)
self.item.setOpacity(1)
self.analysiswidget.spectrumSelector.setValue(1)
self.analysiswidget.spectrumSelector.setMaximum(len(self.analysiswidget.particles2spectra[index]))
selectedPolymer = self.analysiswidget.currentPolymers[specIndex]
self.analysiswidget.polymerIndex = self.analysiswidget.uniquePolymers.index(selectedPolymer)
self.analysiswidget.polymerComboBox.setCurrentIndex(self.analysiswidget.polymerIndex)
#reconnect all widgets:
self.analysiswidget.particleSelector.valueChanged.connect(self.analysiswidget.selectParticle)
self.analysiswidget.spectrumSelector.valueChanged.connect(self.analysiswidget.selectSpectrum)
self.analysiswidget.polymerComboBox.currentIndexChanged.connect(self.analysiswidget.displayNewPolymerType)
else:
self.item.setPixmap(QtGui.QPixmap())
if self.mode == "OpticalScan":
for i, p in zip(self.dataset.fitindices, self.dataset.fitpoints):
p = self.dataset.mapToPixel(p, mode=microscope_mode, force=True)
fititem = FitPosIndicator(i+1, pos=p)
self.scene().addItem(fititem)
self.fititems.append(fititem)
if self.mode == "ParticleDetection" or self.mode == "ParticleAnalysis":
self.prepareAnalysis()
else:
self.fitToWindow()
@QtCore.pyqtSlot()
def resetScanPositions(self):
micMode = ('df' if self.oscanwidget.df_btn.isChecked() else 'bf')
for item in self.scanitems:
self.scene().removeItem(item)
edges, nodes = self.boundaryitems
boundary = []
for n in nodes:
p = n.pos().x(), n.pos().y()
boundary.append(self.dataset.mapToLength(p, self.microscopeMode, force=True))
boundary = np.array(boundary)
# print(boundary)
self.dataset.boundary = boundary
if micMode == 'df':
width, height, angle = self.dataset.imagedim_df
else:
width, height, angle = self.dataset.imagedim_bf
margin = min(width, height)*0.02
wx, wy = width-margin, height-margin
print(wx,wy)
p1 = polygoncovering(boundary, wx, wy)
b2 = boundary.copy()
b2 = b2[:,[1,0]]
p2 = polygoncovering(b2, wy, wx)