diff --git a/.gitignore b/.gitignore
index 97bbc51565f5b9017f678c389a5c1a729486f808..b5150f329a7dcbe83b95759071e90182c4f1e92a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,5 @@ instrumentcom/renishawtesting.py
*.pyc
*.jdx
+
+instrumentcom/thermoFTIRCom.py
diff --git a/gepard_ConfigTemplate.cfg b/gepard_ConfigTemplate.cfg
index 82ec72d6f89d8a8593d85ab855fb6a98a353cb7a..9e77d08174d2a30851b60b3d32bf1a50c6764bfc 100644
--- a/gepard_ConfigTemplate.cfg
+++ b/gepard_ConfigTemplate.cfg
@@ -11,6 +11,8 @@ raman_interface = SIMULATED_RAMAN_CONTROL
[General Microscope Setup]
magnification = 20
+# The scale factor allows downscaling the video image of the microscope camera in order to reduce final image size
+videoImageScaleFactor = 1.0
[Renishaw]
#information specific for renishaw control
diff --git a/gui/opticalscanui.py b/gui/opticalscanui.py
index 86dd5ae2db7dbdb890007783e676a823a5c57321..fa535002ee0a43adfa9f5f98b19e11c07a42c7c5 100644
--- a/gui/opticalscanui.py
+++ b/gui/opticalscanui.py
@@ -29,19 +29,20 @@ import logging.handlers
import cv2
from time import localtime, strftime
from typing import List, TYPE_CHECKING
-from ..imagestitch import imageStacking
-from ..helperfunctions import cv2imread_fix, cv2imwrite_fix, getInstrumentControl, positionWidgetOnScreen
-from ..opticalbackground import BackGroundManager
from .uielements import TimeEstimateProgressbar
from .zlevelsetter import ZLevelSetter
+from ..imagestitch import imageStacking
+from ..helperfunctions import cv2imread_fix, cv2imwrite_fix, positionWidgetOnScreen
+from ..opticalbackground import BackGroundManager
from ..scenePyramid import ScenePyramid
from ..gepardlogging import setDefaultLoggingConfig
+from ..instrumentcom.instrumentComBase import InstrumentComBase
if TYPE_CHECKING:
from ..sampleview import SampleView
-def scan(path, sol, zpositions, grid, controlclass, dataqueue,
+def scan(path, sol, zpositions, grid, instrctrlClass, videoScaleFac: float, dataqueue,
stopevent, logpath, ishdr=False):
if ishdr:
merge_mertens = cv2.createMergeMertens()
@@ -55,7 +56,8 @@ def scan(path, sol, zpositions, grid, controlclass, dataqueue,
logger.info('starting new optical scan')
try:
- instrctrl = controlclass(logger)
+ instrctrl: InstrumentComBase = instrctrlClass(logger)
+ instrctrl.setVideoScaleFactor(videoScaleFac)
instrctrl.updateImageConfig(os.path.dirname(logpath))
instrctrl.connect()
zlist = list(enumerate(zpositions))
@@ -707,7 +709,7 @@ class OpticalScanUI(QtWidgets.QWidget):
self.dataqueue = Queue()
logpath = os.path.join(self.dataset.path, 'opticalScanLog.txt')
self.process = Process(target=scan, args=(path, sol, self.dataset.zpositions,
- self.dataset.grid, self.instrctrl.__class__,
+ self.dataset.grid, self.instrctrl.__class__, self.instrctrl.videoScaleFactor,
self.dataqueue, self.processstopevent,
logpath, self.hdrcheck.isChecked()))
self.process.start()
diff --git a/helperfunctions.py b/helperfunctions.py
index cabd017cbc99ad041fe2d77ef7df1435bdda45d4..533e27fb519cef22ca416ca8dc6fefc05e52583c 100644
--- a/helperfunctions.py
+++ b/helperfunctions.py
@@ -22,7 +22,6 @@ If not, see .
import numpy as np
import cv2
import os
-import sys
from PyQt5 import QtWidgets, QtCore
try:
@@ -32,8 +31,10 @@ except ImportError:
skimread = None
skimsave = None
-from .instrumentcom.instrumentComBase import InstrumentComBase
from logging import Logger
+from typing import TYPE_CHECKING
+if TYPE_CHECKING:
+ from .instrumentcom.instrumentComBase import InstrumentComBase
def cv2imread_fix(fname, flags=cv2.IMREAD_COLOR):
@@ -105,11 +106,12 @@ def polygoncovering(boundary, wx, wy):
return poslist
-def getInstrumentControl(controlclass: InstrumentComBase, logger: Logger) -> InstrumentComBase:
+def getInstrumentControl(controlclass: 'InstrumentComBase', logger: Logger) -> 'InstrumentComBase':
simulatedInterface: bool = False
if 'simulatedInterface' in controlclass.__dict__.keys():
if controlclass.__dict__['simulatedInterface'] == True:
simulatedInterface = True
+
if simulatedInterface:
instrctrl = controlclass(logger, ui=False)
else:
@@ -131,7 +133,7 @@ def needsFTIRAperture(sampleview) -> bool:
return needsAperture
-def lightModeSwitchNeeded(instrctrl: InstrumentComBase) -> bool:
+def lightModeSwitchNeeded(instrctrl: 'InstrumentComBase') -> bool:
switchNeeded: bool = False
if instrctrl.name == 'RenishawCOM':
instrctrl.connect()
diff --git a/instrumentcom/WITecCOM.py b/instrumentcom/WITecCOM.py
index a588640bb9a28cfb7e0ab6889393015afb173518..e922c74c4d7a1aad45ab90a878eda75075e814b6 100644
--- a/instrumentcom/WITecCOM.py
+++ b/instrumentcom/WITecCOM.py
@@ -380,6 +380,7 @@ class WITecCOM(InstrumentComBase):
self.ImageNameMan.SetValue(fname)
self.ImageSaveMan.OperateTrigger()
sleep(.1)
+ self._scaleVideoImage(fname)
@comErrorRepeater
def getImageDimensions(self, mode = 'df'):
diff --git a/instrumentcom/instrumentComBase.py b/instrumentcom/instrumentComBase.py
index 4d168bd7c22f773dc654b5791973e093eb366897..0b43a4f3cd5c9ca9b533d87c34413dc7e8f23bd8 100644
--- a/instrumentcom/instrumentComBase.py
+++ b/instrumentcom/instrumentComBase.py
@@ -18,15 +18,32 @@ You should have received a copy of the GNU General Public License
along with this program, see COPYING.
If not, see .
"""
+import cv2
+from ..helperfunctions import cv2imread_fix, cv2imwrite_fix
class InstrumentComBase(object):
+ videoScaleFactor: float = 1.0
+
+ @classmethod
+ def setVideoScaleFactor(cls, newFac) -> None:
+ cls.videoScaleFactor = float(newFac)
+
def __init__(self, logger=None):
self.name = None
self.connected = False
self.timeseries = False
self.logger = logger
-
+
+ def _scaleVideoImage(self, imagePath: str) -> None:
+ """
+ For convenience.. Takes the image at the indicated path and scales it to the videoScaleFactor.
+ """
+ img = cv2imread_fix(imagePath)
+ img = cv2.resize(img, None, fx=self.videoScaleFactor, fy=self.videoScaleFactor)
+ img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
+ cv2imwrite_fix(imagePath, img)
+
def getRamanPositionShift(self):
""" Compute the shift between laser spot and image center"""
raise NotImplementedError
@@ -60,10 +77,6 @@ class InstrumentComBase(object):
""" Get the image width and height in um and the orientation angle in degrees.
"""
raise NotImplementedError
-
- # IT IS NOT NEEDED, ISN'T IT??
- # def startSinglePointScan(self):
- # raise NotImplementedError
def initiateMeasurement(self, specScanSettings):
raise NotImplementedError
diff --git a/instrumentcom/instrumentConfig.py b/instrumentcom/instrumentConfig.py
index 8dca512826a19e85f9fcc9ce2d8d8d958693b321..0bd140a4cc57581d47afb1bee43003d98b1ea5d8 100644
--- a/instrumentcom/instrumentConfig.py
+++ b/instrumentcom/instrumentConfig.py
@@ -29,6 +29,7 @@ config = configparser.ConfigParser()
config.read(os.path.join(defaultPath, 'gepard.cfg'))
interface = "SIMULATED_RAMAN_CONTROL"
+videoImgScale = 1.0
class SpecScanParameter(object):
@@ -63,7 +64,6 @@ class SpecScanParameter(object):
try:
defaultPath = config["Defaults"]["file_path"]
- print('default Path is now:', defaultPath)
except KeyError:
pass
@@ -72,6 +72,12 @@ try:
except KeyError:
pass
+try:
+ videoImgScale = config["General Microscope Setup"]["videoImageScaleFactor"]
+except KeyError:
+ pass
+
+
if interface == "SIMULATED_RAMAN_CONTROL":
from .simulated.simulatedraman import SimulatedRaman
InstrumentControl = SimulatedRaman
@@ -95,7 +101,6 @@ elif interface == "RENISHAW_CONTROL":
InstrumentControl.cam_df_dims = [float(df_dims[0]), float(df_dims[1])]
except:
print('Invalid image dimensions in config file!')
-# InstrumentControl.defaultMeasTemplate = config["Renishaw"]["defaultMeasTemplate"]
InstrumentControl.measTemplatePath = config["Renishaw"]["measTemplatePath"]
print(InstrumentControl.measTemplatePath)
InstrumentControl.specScanParameters = InstrumentControl.updateSpecScanParameters(InstrumentControl, InstrumentControl.measTemplatePath)
@@ -106,3 +111,5 @@ elif interface == "THERMO_FTIR":
from .thermoFTIRCom import ThermoFTIRCom
InstrumentControl = ThermoFTIRCom
simulatedRaman = False
+
+InstrumentControl.setVideoScaleFactor(videoImgScale)
diff --git a/instrumentcom/simulated/imageGenerator.py b/instrumentcom/simulated/imageGenerator.py
index 419c055ee3e4b033dca348175aac94413b0370d7..869c1aa88f4c3a07910fdc4132d5ffc286262646 100644
--- a/instrumentcom/simulated/imageGenerator.py
+++ b/instrumentcom/simulated/imageGenerator.py
@@ -122,12 +122,8 @@ class FakeParticle:
class FakeCamera:
# TODO: Implement a small angle to simulate a tilted camera!
def __init__(self):
- self.imgDims: Tuple[int, int] = (500, 250) # width, height of camera imgage
+ self.imgDims: Tuple[int, int] = (600, 350) # width, height of camera imgage in pixel
self.pixelscale: float = 1.0 # µm/px
- self.sizeScale: float = 100.0 # smaller values make particles rendered smaller and vice versa
- self.threshold: float = 0.7 # threshold for determining particles. Larger values -> smaller particles
- self.numZLevels: int = 7 # number of z-levels cached for faking depth of field
- self.maxZDiff: float = 100 # max difference in z that is simulated.
self.currentImage: np.ndarray = np.zeros((self.imgDims[1], self.imgDims[0], 3))
self.fakeFilter: FakeFilter = FakeFilter()
diff --git a/instrumentcom/simulated/simulatedStage.py b/instrumentcom/simulated/simulatedStage.py
index 39562d7f3efa2d9415f3d07ae365fb5f7a8287df..8e83684f6fab801aac4477c2005089bf57355d6a 100644
--- a/instrumentcom/simulated/simulatedStage.py
+++ b/instrumentcom/simulated/simulatedStage.py
@@ -26,7 +26,7 @@ import cv2
import json
import numpy as np
from typing import List
-from .imageGenerator import FakeCamera
+from .imageGenerator import FakeCamera, FakeFilter
from ..instrumentComBase import InstrumentComBase
from ...helperfunctions import getAppFolder
@@ -266,23 +266,23 @@ class SimulatedStageUI(QtWidgets.QWidget):
self.stageParent.moveToPosition(newPos[0], newPos[1], newPos[2])
- def _moveToPresetPosition(self, btn: QtWidgets.QPushButton, stepSize: float = 1000) -> None:
+ def _moveToPresetPosition(self, btn: QtWidgets.QPushButton) -> None:
label: str = btn.text()
+ filter: FakeFilter = self.stageParent.camera.fakeFilter
+ margin: float = 0.9
newPos: List[float] = [0.0, 0.0, 0.0]
if label == 'UpperLeft':
- newPos[0] -= stepSize
- newPos[1] += stepSize
+ newPos[0] = filter.xRange[0] * margin
+ newPos[1] = filter.yRange[1] * margin
elif label == 'UpperRight':
- newPos[0] += stepSize
- newPos[1] += stepSize
+ newPos[0] = filter.xRange[1] * margin
+ newPos[1] = filter.yRange[1] * margin
elif label == 'LowerLeft':
- newPos[0] -= stepSize
- newPos[1] -= stepSize
+ newPos[0] = filter.xRange[0] * margin
+ newPos[1] = filter.yRange[0] * margin
elif label == 'LowerRight':
- newPos[0] += stepSize
- newPos[1] -= stepSize
- elif label == 'Center':
- pass
+ newPos[0] = filter.xRange[1] * margin
+ newPos[1] = filter.yRange[0] * margin
self.stageParent.moveToPosition(newPos[0], newPos[1], newPos[2])
diff --git a/instrumentcom/simulated/simulatedraman.py b/instrumentcom/simulated/simulatedraman.py
index 3f58101ab59e81a3da2a7c16d2c86bc58f6b5fbe..4f79730e24df40b6097bb55da3314af8d9434975 100644
--- a/instrumentcom/simulated/simulatedraman.py
+++ b/instrumentcom/simulated/simulatedraman.py
@@ -43,7 +43,6 @@ class SimulatedRaman(InstrumentComBase):
self.znum = 4
self.gridnum = 36
self.positionindex = 0
- self.imageindex = 0
def getRamanPositionShift(self):
return 0., 0.
@@ -51,7 +50,6 @@ class SimulatedRaman(InstrumentComBase):
def connect(self):
self.stage.connect()
self.connected = True
- self.imageindex = 0
return True
def disconnect(self):
@@ -84,7 +82,7 @@ class SimulatedRaman(InstrumentComBase):
def saveImage(self, fname):
assert self.connected
cv2imwrite_fix(fname, self.stage.getCurrentCameraImage())
- self.imageindex = (self.imageindex+1) % (self.znum*self.gridnum)
+ self._scaleVideoImage(fname)
def getImageDimensions(self, mode='df'):
"""
@@ -92,7 +90,9 @@ class SimulatedRaman(InstrumentComBase):
"""
assert self.connected
camDims: tuple = self.stage.camera.imgDims
- return camDims[0], camDims[1], 0 # TODO: RE-Implement a small angle to simulate a tilted camera!
+ # TODO: RE-Implement a small angle to simulate a tilted camera!
+ angle: float = 0.0
+ return camDims[0], camDims[1], angle
def startSinglePointScan(self):
assert self.connected
diff --git a/unittests/test_gepard.py b/unittests/test_gepard.py
index 32734a3aaa7a29edbcedd8491aa332170feea0b7..1aa0bdbc051b8cc8cf93543a190a64705dd524fe 100644
--- a/unittests/test_gepard.py
+++ b/unittests/test_gepard.py
@@ -12,20 +12,18 @@ from typing import TYPE_CHECKING
from ..sampleview import SampleView
from ..dataset import DataSet
from ..analysis.particleContainer import ParticleContainer
-from ..analysis.particleAndMeasurement import Measurement
from ..instrumentcom.instrumentComBase import InstrumentComBase
-from ..instrumentcom.instrumentConfig import defaultPath
+from ..instrumentcom.simulated.simulatedStage import SimulatedStage
from ..gui.opticalscanui import OpticalScanUI, PointCoordinates
from ..gui.detectionview import ParticleDetectionView, ImageView
from ..gui.specscanui import SpecScanUI
-from ..gui.viewItems.detectItems import SeedPoint
from ..gui.viewItemHandler import ViewItemHandler
from ..workmodes import ModeHandler, ModeOpticalScan, ModeParticleDetection, ModeSpectrumScan
+
if TYPE_CHECKING:
from ..__main__ import GEPARDMainWindow
-
def testGepard(gepard):
gepard.testCase = TestGepard(gepard)
gepard.testCase.start_automated_test()
@@ -67,17 +65,19 @@ class TestGepard(unittest.TestCase):
# SET UP OPTICAL SCAN
moveMargin: int = 300
- curPos: tuple = self.instrctrl.getPosition()
self.assertEqual(type(self.modeHandler.activeMode), ModeOpticalScan)
oscanWidget: OpticalScanUI = self.modeHandler.oscanMode.widget
self.assertEqual(type(oscanWidget), OpticalScanUI)
self.assertTrue(oscanWidget.isVisible())
oscanWidget.zLevelSetter.numLevelsSpinbox.setValue(3)
+ simulatedStage: SimulatedStage = self.sampleview.instrctrl.stage
+ simulatedStage.moveToPosition(0, 0, 0)
+
points: PointCoordinates = oscanWidget.points
points.read(0)
- self.instrctrl.moveToAbsolutePosition(curPos[0] + moveMargin, curPos[1] + moveMargin, curPos[2])
+ self.instrctrl.moveToAbsolutePosition(moveMargin, moveMargin, 0)
points.read(1)
- self.instrctrl.moveToAbsolutePosition(curPos[0] - moveMargin, curPos[1] - moveMargin, curPos[2])
+ self.instrctrl.moveToAbsolutePosition(-moveMargin, -moveMargin, 0)
points.read(2)
oscanWidget.pareaselect.click()