Commit 819efb02 authored by Robert's avatar Robert Committed by Robert Ohmacht

-initial integration of ScenePyramid from GepardEvaluation into Gepard

parent 1fff5fef
...@@ -135,6 +135,9 @@ class DataSet(object): ...@@ -135,6 +135,9 @@ class DataSet(object):
self.coordinatetransform = None # if imported form extern source coordinate system may be rotated self.coordinatetransform = None # if imported form extern source coordinate system may be rotated
self.signx = 1. self.signx = 1.
self.signy = -1. self.signy = -1.
# tiling parameters
self.pyramidParams = None
# parameters specifically for raman scan # parameters specifically for raman scan
self.pshift = None # shift of raman scan position relative to image center self.pshift = None # shift of raman scan position relative to image center
...@@ -169,6 +172,12 @@ class DataSet(object): ...@@ -169,6 +172,12 @@ class DataSet(object):
def __eq__(self, other): def __eq__(self, other):
return recursiveDictCompare(self.__dict__, other.__dict__) return recursiveDictCompare(self.__dict__, other.__dict__)
def getPyramidParams(self):
return self.pyramidParams
def setPyramidParams(self, pyramid_params):
self.pyramidParams = pyramid_params
def getPixelScale(self, mode=None): def getPixelScale(self, mode=None):
if mode is None: if mode is None:
...@@ -275,6 +284,12 @@ class DataSet(object): ...@@ -275,6 +284,12 @@ class DataSet(object):
self.__dict__.update(loadData(fname).__dict__) self.__dict__.update(loadData(fname).__dict__)
return fname return fname
def getTilePath(self):
scandir = os.path.join(self.path, "tiles")
if not os.path.exists(scandir):
os.mkdir(scandir)
return scandir
def getScanPath(self): def getScanPath(self):
scandir = os.path.join(self.path, "scanimages") scandir = os.path.join(self.path, "scanimages")
if not os.path.exists(scandir): if not os.path.exists(scandir):
......
...@@ -27,6 +27,7 @@ from threading import Thread ...@@ -27,6 +27,7 @@ from threading import Thread
from .segmentation import Segmentation from .segmentation import Segmentation
from .analysis.particleCharacterization import getParticleStatsWithPixelScale, loadZValImageFromDataset from .analysis.particleCharacterization import getParticleStatsWithPixelScale, loadZValImageFromDataset
from .errors import InvalidParticleError from .errors import InvalidParticleError
from .scenePyramid import ScenePyramid
Nscreen = 1000 Nscreen = 1000
...@@ -269,14 +270,15 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -269,14 +270,15 @@ class ParticleDetectionView(QtWidgets.QWidget):
imageUpdate = QtCore.pyqtSignal(str, name='imageUpdate') #str = 'df' (= darkfield) or 'bf' (=bright field) 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, pyramid: ScenePyramid, dataset, parent=None):
super().__init__(parent, QtCore.Qt.Window) super().__init__(parent, QtCore.Qt.Window)
self.dataset = self.verifySeedpoints(dataset) self.dataset = self.verifySeedpoints(dataset)
self.img = img self.pyramid = pyramid
self.imgclip = 0,0,0,0 self.img = pyramid.getFullImage(.5)
self.imgclip = 0, 0, 0, 0
self.seg = Segmentation(self.dataset, self) self.seg = Segmentation(self.dataset, self)
self.thread = None self.thread = None
self.view = parent self.view : QtWidgets.QGraphicsView = parent
vbox = QtWidgets.QVBoxLayout() vbox = QtWidgets.QVBoxLayout()
hbox = QtWidgets.QHBoxLayout() hbox = QtWidgets.QHBoxLayout()
...@@ -529,33 +531,69 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -529,33 +531,69 @@ class ParticleDetectionView(QtWidgets.QWidget):
self.updateImageSeeds() self.updateImageSeeds()
def setImageCenter(self, center=None): def setImageCenter(self, center=None):
'''
as more than the tiles are part of the scene
bounding rect may be bigger than just a rect around the tiles
tiles should be grouped
'''
width, height = self.pyramid.getBoundingRectDim()
if center is None: if center is None:
centerx = self.img.shape[1]//2 centerx = width//2
centery = self.img.shape[0]//2 centery = height//2
else: else:
centerx, centery = center centerx, centery = center
if self.img.shape[0]<Nscreen:
centery = self.img.shape[0]//2 if height < Nscreen:
if self.img.shape[1]<Nscreen: centery = height//2
centerx = self.img.shape[1]//2 if width < Nscreen:
centerx = width//2
if not self.drag: if not self.drag:
self.lastcenter = centerx, centery self.lastcenter = centerx, centery
n1, n2 = int(centery-Nscreen//2),int(centery+Nscreen//2+1)
m1, m2 = int(centerx-Nscreen//2),int(centerx+Nscreen//2+1) y1, y2 = centery-Nscreen//2, centery+Nscreen//2+1
if n1<0: x1, x2 = centerx-Nscreen//2, centerx+Nscreen//2+1
n2 -= n1 if y1 < 0:
n1 = 0 y2 -= y1
if n2>self.img.shape[0]: y1 = 0
n1 -= n2-self.img.shape[0] if y2 > height:
if n1<0: n1 = 0 y1 -= y2-height
n2 = self.img.shape[0] if y1 < 0:
if m1<0: y1 = 0
m2 -= m1 y2 = height
m1 = 0 if x1 < 0:
if m2>self.img.shape[1]: x2 -= x1
m1 -= m2-self.img.shape[1] x1 = 0
if m1<0: m1 = 0 if x2 > width:
m2 = self.img.shape[1] x1 -= x2-width
if x1 < 0:
x1 = 0
x2 = width
self.imgclip = int(y1), int(y2), int(x1), int(x2)
self.subimg, pix = self.pyramid.getSubImage(self.imgclip)
'''
img = QtGui.QImage(x2 - x1, y2 - y1, QtGui.QImage.Format_RGB888)
self.view.scene().render(
QtGui.QPainter(img),
QtCore.QRectF(0, 0, img.width(), img.height()),
#QtCore.QRectF(x1 + x0, y1 + y0, x2 - x1, y2 - y1)
QtCore.QRectF(x1, y1, x2 - x1, y2 - y1)
)
#pix = self.view.grab(QtCore.QRect(x1 + x0, y1 + y0, x2 - x1, y2 - y1))
# @see https://stackoverflow.com/a/11399959
#img = pix.toImage().convertToFormat(QtGui.QImage.Format_RGB888)
ptr = img.bits()
#ptr.setsize(img.byteCount())
ptr.setsize(img.height() * img.width() * 3)
self.subimg = np.asarray(ptr).reshape(img.height(), img.width(), 3)
pix = QtGui.QPixmap()
pix.convertFromImage(img)
'''
'''
sub = self.img[n1:n2,m1:m2,:].copy() sub = self.img[n1:n2,m1:m2,:].copy()
self.imgclip = n1,n2,m1,m2 self.imgclip = n1,n2,m1,m2
self.subimg = sub self.subimg = sub
...@@ -564,6 +602,7 @@ class ParticleDetectionView(QtWidgets.QWidget): ...@@ -564,6 +602,7 @@ class ParticleDetectionView(QtWidgets.QWidget):
pix = QtGui.QPixmap() pix = QtGui.QPixmap()
pix.convertFromImage(QtGui.QImage(sub.data, width, height, pix.convertFromImage(QtGui.QImage(sub.data, width, height,
bytesPerLine, QtGui.QImage.Format_RGB888)) bytesPerLine, QtGui.QImage.Format_RGB888))
'''
self.imglabel.clearData() self.imglabel.clearData()
self.imglabel.setPixmap(pix) self.imglabel.setPixmap(pix)
self.updateImageSeeds() self.updateImageSeeds()
......
...@@ -27,8 +27,9 @@ from .helperfunctions import cv2imread_fix, cv2imwrite_fix ...@@ -27,8 +27,9 @@ from .helperfunctions import cv2imread_fix, cv2imwrite_fix
from .analysis.particleContainer import ParticleContainer from .analysis.particleContainer import ParticleContainer
from .analysis import particleCharacterization as pc from .analysis import particleCharacterization as pc
from .errors import InvalidParticleError from .errors import InvalidParticleError
from .scenePyramid import ScenePyramid
currentVersion = 4 currentVersion = 5
def legacyConversion(dset, recreatefullimage=False): def legacyConversion(dset, recreatefullimage=False):
if dset.version==0: if dset.version==0:
...@@ -110,6 +111,12 @@ def legacyConversion(dset, recreatefullimage=False): ...@@ -110,6 +111,12 @@ def legacyConversion(dset, recreatefullimage=False):
removeLegacyAttributes(dset) removeLegacyAttributes(dset)
dset.version = 4 dset.version = 4
dset.save() dset.save()
if dset.version == 4:
print("Converting legacy version 4 to 5")
ScenePyramid.createFromFullImage(dset)
dset.version = 5
dset.save()
# add later conversion for higher version numbers here # add later conversion for higher version numbers here
......
...@@ -106,7 +106,7 @@ class BackGroundManager(QtWidgets.QWidget): ...@@ -106,7 +106,7 @@ class BackGroundManager(QtWidgets.QWidget):
p0 = [points[:,0].min(), points[:,1].max()] p0 = [points[:,0].min(), points[:,1].max()]
p1 = [points[:,0].max(), points[:,1].min()] p1 = [points[:,0].max(), points[:,1].min()]
reply = QtWidgets.QMessageBox.question(self, 'Message',f"The stage will move {round(3*width)} in x and {round(3*height)} in y.\nContinue?", reply = QtWidgets.QMessageBox.question(self, 'Message', f"The stage will move {round(3*width)} in x and {round(3*height)} in y.\nContinue?",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No) QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes: if reply == QtWidgets.QMessageBox.Yes:
fullimg = None fullimg = None
......
...@@ -31,6 +31,7 @@ from time import time ...@@ -31,6 +31,7 @@ from time import time
import datetime import datetime
from .opticalbackground import BackGroundManager from .opticalbackground import BackGroundManager
from .zlevelsetter import ZLevelSetter from .zlevelsetter import ZLevelSetter
from .scenePyramid import ScenePyramid
def scan(path, sol, zpositions, grid, controlclass, dataqueue, def scan(path, sol, zpositions, grid, controlclass, dataqueue,
stopevent, logpath='', ishdr=False): stopevent, logpath='', ishdr=False):
...@@ -84,10 +85,10 @@ def scan(path, sol, zpositions, grid, controlclass, dataqueue, ...@@ -84,10 +85,10 @@ def scan(path, sol, zpositions, grid, controlclass, dataqueue,
def subtractBackground(image, background): def subtractBackground(image, background):
avg = np.mean(background) avg = np.mean(background)
subtracted = np.clip(np.array(image - background + avg, dtype = np.uint8), 0, 255) subtracted = np.clip(np.array(image - background + avg, dtype=np.uint8), 0, 255)
return subtracted return subtracted
def loadAndPasteImage(srcnames, fullimage, fullzval, width, height, def loadAndPasteImage(srcnames, pyramid, fullzval, width, height,
rotationvalue, p0, p1, p, background=None): rotationvalue, p0, p1, p, background=None):
colimgs = [] colimgs = []
for name in srcnames: for name in srcnames:
...@@ -102,15 +103,22 @@ def loadAndPasteImage(srcnames, fullimage, fullzval, width, height, ...@@ -102,15 +103,22 @@ def loadAndPasteImage(srcnames, fullimage, fullzval, width, height,
c, s = np.cos(np.radians(rotationvalue)), np.sin(np.radians(rotationvalue)) c, s = np.cos(np.radians(rotationvalue)), np.sin(np.radians(rotationvalue))
dx, dy = (x-p0[0])/width*img.shape[1], (p0[1]-y)/height*img.shape[0] dx, dy = (x-p0[0])/width*img.shape[1], (p0[1]-y)/height*img.shape[0]
M = np.float32([[c,s,dx],[-s,c,dy]]) M = np.float32([[c, s, dx], [-s, c, dy]])
if fullimage is not None: dst = None
cv2.warpAffine(img, M, (Nx, Ny), fullimage, borderMode=cv2.BORDER_TRANSPARENT)
cv2.warpAffine(zval, M, (Nx, Ny), fullzval, borderMode=cv2.BORDER_TRANSPARENT) if pyramid is not None:
dst = fullimage if fullzval is not None:
zval = fullzval cv2.warpAffine(zval, M, (Nx, Ny), fullzval, borderMode=cv2.BORDER_TRANSPARENT)
else: zval = fullzval
dst = cv2.warpAffine(img, M, (Nx, Ny)) else:
zval = cv2.warpAffine(zval, M, (Nx, Ny)) zval = cv2.warpAffine(zval, M, (Nx, Ny))
pyramid.addSrcTile(
img,
np.float32([[c, s, 0], [-s, c, 0]]),
(dx, dy),
(Nx, Ny)
)
return dst, zval return dst, zval
...@@ -231,12 +239,13 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -231,12 +239,13 @@ class OpticalScan(QtWidgets.QWidget):
def __init__(self, ramanctrl, dataset, logpath='', parent=None): def __init__(self, ramanctrl, dataset, logpath='', parent=None):
super().__init__(parent, QtCore.Qt.Window) super().__init__(parent, QtCore.Qt.Window)
self.logpath = logpath self.logpath = logpath
self.view = parent self.view: QtWidgets.QGraphicsView = parent
mainLayout = QtWidgets.QVBoxLayout() mainLayout = QtWidgets.QVBoxLayout()
pointgroup = QtWidgets.QGroupBox("Point coordinates [µm]", self) pointgroup = QtWidgets.QGroupBox("Point coordinates [µm]", self)
self.ramanctrl = ramanctrl self.ramanctrl = ramanctrl
self.dataset = dataset self.dataset = dataset
self.pyramid: ScenePyramid = None
self.positions = [] self.positions = []
self.process = None self.process = None
self.points = PointCoordinates(5, self.ramanctrl, self) self.points = PointCoordinates(5, self.ramanctrl, self)
...@@ -425,6 +434,9 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -425,6 +434,9 @@ class OpticalScan(QtWidgets.QWidget):
self.boundaryUpdate.emit() self.boundaryUpdate.emit()
self.prun.setEnabled(True) self.prun.setEnabled(True)
def setPyramid(self, pyramid):
self.pyramid = pyramid
def resetDataset(self, ds): def resetDataset(self, ds):
self.dataset = ds self.dataset = ds
self.points.createWidgets(5, list(zip(ds.fitindices,ds.fitpoints))) self.points.createWidgets(5, list(zip(ds.fitindices,ds.fitpoints)))
...@@ -482,22 +494,34 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -482,22 +494,34 @@ class OpticalScan(QtWidgets.QWidget):
Nx, Ny = int((p1[0]-p0[0]+width)/width*img.shape[1]), int((p0[1]-p1[1]+height)/height*img.shape[0]) + 10 # + 10 because of rotation and hopefully it will be small Nx, Ny = int((p1[0]-p0[0]+width)/width*img.shape[1]), int((p0[1]-p1[1]+height)/height*img.shape[0]) + 10 # + 10 because of rotation and hopefully it will be small
c, s = np.cos(np.radians(rotationvalue)), np.sin(np.radians(rotationvalue)) c, s = np.cos(np.radians(rotationvalue)), np.sin(np.radians(rotationvalue))
dx, dy = (x-p0[0])/width*img.shape[1], (p0[1]-y)/height*img.shape[0] dx, dy = (x-p0[0])/width*img.shape[1], (p0[1]-y)/height*img.shape[0]
M = np.float32([[c,s,dx],[-s,c,dy]]) M = np.float32([[c, s, dx], [-s, c, dy]])
dst = cv2.warpAffine(img, M, (Nx, Ny)) #dst = cv2.warpAffine(img, M, (Nx, Ny))
if self.view.imgdata is not None and self.dataset.lastpos is not None: M_rot = np.float32([[c, s, 0], [-s, c, 0]])
lp = self.dataset.lastpos img_rot = cv2.warpAffine(img, M_rot, (img.shape[1], img.shape[0] + 10))
dx, dy = (lp[0]-p0[0])/width*img.shape[1], (p0[1]-lp[1])/height*img.shape[0] # calc new pixel start coords for tile
full = self.view.imgdata # @see https://stackoverflow.com/a/43166421/9880753
M = np.float32([[1,0,dx],[0,1,dy]]) c_dest = cv2.transform(np.float32([[(0, 0)]]), np.float32([[c, s, dx], [-s, c, dy]]))
try:
full = cv2.warpAffine(full, M, (Nx, Ny)) #fails, if image dimensions are >32767x32767px... self.pyramid.addSrcTileSimple(
dst = cv2.max(full, dst) img_rot,
except: (c_dest[0][0][0], c_dest[0][0][1]),
QtWidgets.QMessageBox.critical(self, 'Error', 'Image is too large\nSelect smaller region.') p0
raise )
return
#if self.view.imgdata is not None and self.dataset.lastpos is not None:
# lp = self.dataset.lastpos
# dx, dy = (lp[0]-p0[0])/width*img.shape[1], (p0[1]-lp[1])/height*img.shape[0]
# full = self.view.imgdata
# M = np.float32([[1,0,dx],[0,1,dy]])
# try:
# full = cv2.warpAffine(full, M, (Nx, Ny)) #fails, if image dimensions are >32767x32767px...
# dst = cv2.max(full, dst)
# except:
# QtWidgets.QMessageBox.critical(self, 'Error', 'Image is too large\nSelect smaller region.')
# raise
# return
self.view.imgdata = dst #self.view.imgdata = dst
self.dataset.lastpos = p0 self.dataset.lastpos = p0
self.dataset.maxdim = p0 + p1 self.dataset.maxdim = p0 + p1
self.dataset.readin = False self.dataset.readin = False
...@@ -621,7 +645,8 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -621,7 +645,8 @@ class OpticalScan(QtWidgets.QWidget):
self.progressbar.setEnabled(True) self.progressbar.setEnabled(True)
self.progressbar.setRange(0, len(self.dataset.grid)) self.progressbar.setRange(0, len(self.dataset.grid))
self.progressbar.setValue(0) self.progressbar.setValue(0)
self.view.imgdata = None #self.view.imgdata = None
self.pyramid.resetScene()
self.view.blockUI() self.view.blockUI()
grid = np.asarray(self.dataset.grid) grid = np.asarray(self.dataset.grid)
p0 = [grid[:,0].min(), grid[:,1].max()] p0 = [grid[:,0].min(), grid[:,1].max()]
...@@ -657,7 +682,7 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -657,7 +682,7 @@ class OpticalScan(QtWidgets.QWidget):
else: else:
background_img = None background_img = None
self.view.imgdata, self.dataset.zvalimg = loadAndPasteImage(names, self.view.imgdata, self.dataset.zvalimg, width, height, self.view.imgdata, self.dataset.zvalimg = loadAndPasteImage(names, self.pyramid, self.dataset.zvalimg, width, height,
rotationvalue, p0, p1, p, background=background_img) rotationvalue, p0, p1, p, background=background_img)
self.progressbar.setValue(i+1) self.progressbar.setValue(i+1)
if i>3: if i>3:
...@@ -665,15 +690,19 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -665,15 +690,19 @@ class OpticalScan(QtWidgets.QWidget):
ttot = timerunning*Ngrid/(i+1) ttot = timerunning*Ngrid/(i+1)
time2go = ttot - timerunning time2go = ttot - timerunning
self.progresstime.setText(self.timelabeltext + str(datetime.timedelta(seconds=round(time2go)))) self.progresstime.setText(self.timelabeltext + str(datetime.timedelta(seconds=round(time2go))))
self.imageUpdate.emit(self.view.microscopeMode) # reload image in sampleview, calls loadPixmap
# not needed anymore as the scene gets manipulated directly via self.pyramid
#self.imageUpdate.emit(self.view.microscopeMode)
if i==Ngrid-1: if i==Ngrid-1:
cv2imwrite_fix(self.dataset.getImageName(), cv2.cvtColor(self.view.imgdata, cv2.COLOR_RGB2BGR)) #cv2imwrite_fix(self.dataset.getImageName(), cv2.cvtColor(self.view.imgdata, cv2.COLOR_RGB2BGR))
self.dataset.saveZvalImg() self.dataset.saveZvalImg()
self.process.join() self.process.join()
self.dataqueue.close() self.dataqueue.close()
self.dataqueue.join_thread() self.dataqueue.join_thread()
self.pyramid.toDataset()
if self.deleteImgChecker.isChecked(): if self.deleteImgChecker.isChecked():
path = self.dataset.getScanPath() path = self.dataset.getScanPath()
files = os.listdir(path) files = os.listdir(path)
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment