def __init__(self, lightToSequence, lightToIsOnDuringAcquisition, **kwargs): # Convert from light source names to light handlers. self.lightToSequence = {} for name, sequence in lightToSequence.items(): handler = depot.getHandlerWithName(name) self.lightToSequence[handler] = sequence self.lightToIsOnDuringAcquisition = {} for name, isOn in lightToIsOnDuringAcquisition.items(): handler = depot.getHandlerWithName(name) self.lightToIsOnDuringAcquisition[handler] = isOn # Call the ZStackExperiment constructor with all of our remaining # parameters, which are in the "kwargs" dictionary object. super().__init__(**kwargs)
def augmentParams(self, params): self.saveSettings() params['settlingTime'] = guiUtils.tryParseNum(self.settlingTimeControl, float) params['startV'] = guiUtils.tryParseNum(self.startVControl, float) params['maxV'] = guiUtils.tryParseNum(self.maxVControl, float) params['vSteps'] = guiUtils.tryParseNum(self.vStepsControl) params['polarizerHandler'] = depot.getHandlerWithName('SI polarizer') return params
def augmentParams(self, params): self.saveSettings() params['numAngles'] = 3 params['numPhases'] = 5 params['collectionOrder'] = self.siCollectionOrder.GetStringSelection() params['angleHandler'] = depot.getHandlerWithName('SI angle') params['phaseHandler'] = depot.getHandlerWithName('SI phase') params['polarizerHandler'] = depot.getHandlerWithName('SI polarizer') params['slmHandler'] = depot.getHandler('slm', depot.EXECUTOR) compensations = {} for i, light in enumerate(self.allLights): val = guiUtils.tryParseNum(self.bleachCompensations[i], float) if val: # Convert from percentage to multiplier compensations[light] = .01 * float(val) else: compensations[light] = 0 params['bleachCompensations'] = compensations return params
def takeImage(self): if not self.digitalClients: # No triggered devices registered. return camlines = sum([1<<self.digitalClients[cam] for cam in self.activeCameras]) # We want to know if there are cameras using rolling shutter. If so, cameras must be triggered in advance exposureStartTime = [cam.getTimeBetweenExposures() for cam in self.activeCameras if cam.getShutteringMode() == ElectronicShutteringMode.ROLLING] exposureStartTime = max(exposureStartTime, default=0) if camlines == 0: # No cameras to be triggered. return ltpairs = [] for light in self.activeLights: lline = 1 << self.digitalClients[light] ltime = light.getExposureTime() ltpairs.append((lline, ltime)) # Sort by exposure time ltpairs.sort(key = lambda item: item[1]) # Generate a sequence of (time, digital state) # TODO: currently uses bulb exposure; should support other modes. if ltpairs: # Start by all active cameras and lights. state = camlines | functools.reduce(operator.ior, list(zip(*ltpairs))[0]) if exposureStartTime != 0: seq = [(0, camlines)] seq.append((exposureStartTime, state)) # Switch off each light as its exposure time expires. for lline, ltime in ltpairs: state -= lline seq.append((exposureStartTime + ltime, state)) else: # No lights. Just trigger the cameras. seq = [(0, camlines)] # If there is an ambient light enabled, extend exposure as # necessary (see issue #669). ambient = depot.getHandlerWithName('Ambient') if ambient is not None and ambient.getIsEnabled(): t = ambient.getExposureTime() if t > seq[-1][0]: seq.append((ambient.getExposureTime(), 0)) # Switch all lights and cameras off. seq.append( (seq[-1][0] + 1, 0) ) if self.callbacks.get('runSequence', None): self.callbacks['runSequence'](seq) else: self.softSequence(seq)
def takeImage(self): if not self.digitalClients: # No triggered devices registered. return camlines = sum( [1 << self.digitalClients[cam] for cam in self.activeCameras]) if camlines == 0: # No cameras to be triggered. return ltpairs = [] for light in self.activeLights: lline = 1 << self.digitalClients[light] ltime = light.getExposureTime() ltpairs.append((lline, ltime)) # Sort by exposure time ltpairs.sort(key=lambda item: item[1]) # Generate a sequence of (time, digital state) # TODO: currently uses bulb exposure; should support other modes. if ltpairs: # Start by all active cameras and lights. state = camlines | functools.reduce(operator.ior, list(zip(*ltpairs))[0]) seq = [(0, state)] # Switch off each light as its exposure time expires. for lline, ltime in ltpairs: state -= lline seq.append((ltime, state)) else: # No lights. Just trigger the cameras. seq = [(0, camlines)] ambient = depot.getHandlerWithName('ambient') # If ambient light is enabled, extend exposure if necessary. if ambient.getIsEnabled(): t = ambient.getExposureTime() if t > seq[-1][0]: seq.append((ambient.getExposureTime(), 0)) # Switch all lights and cameras off. seq.append((seq[-1][0] + 1, 0)) if self.callbacks.get('runSequence', None): self.callbacks['runSequence'](seq) else: self.softSequence(seq)
def setDetMode(self, mode): for mirrorIndex, isUp in self.modeToFlips[mode]: self.flipDownUp(mirrorIndex, isUp) for button in self.detPathButtons: button.setActive(button.GetLabel() == mode) self.curDetMode = mode #IMD 20150129 - flipping buttons for detection path also changes objective # set correct pixel size and image orientation objectiveHandler = depot.getHandlerWithName('objective') if mode == 'with AO & 85 nm pixel size': if (objectiveHandler.curObjective != '63x85nm'): objectiveHandler.changeObjective('63x85nm') print("Change objective 85 nm pixel") elif mode == 'w/o AO & 209 nm pixel size': if (objectiveHandler.curObjective != '63x209nm'): objectiveHandler.changeObjective('63x209nm') print("Change objective 209 nm pixel")
def onLoadExposureSettings(self, event=None): dialog = wx.FileDialog( self, style=wx.FD_OPEN, wildcard='*.txt', message="Please select the settings file to load.", defaultDir=cockpit.util.files.getUserSaveDir()) if dialog.ShowModal() != wx.ID_OK: # User cancelled. self.pathButton.setOption(self.currentPath) return handle = open(dialog.GetPath(), 'r') modeName = os.path.splitext(os.path.basename(handle.name))[0] #get name for new mode # abuse get value dialog which will also return a string. name = cockpit.gui.dialogs.getNumberDialog.getNumberFromUser( parent=self.topPanel, default=modeName, title='New Path Name', prompt='Name') if name not in self.paths: self.pathList.append(name) self.paths[name] = json.loads('\n'.join(handle.readlines())) handle.close() events.publish('load exposure settings', self.paths[name]) #update button list self.pathButton.setOptions( map(lambda name: (name, lambda n=name: self.setPath(n)), self.pathList)) #and set button value. self.pathButton.setOption(name) self.currentPath = name # If we're using the listbox approach to show/hide light controls, # then make sure all enabled lights are shown and vice versa. if self.lightList is not None: for i, name in enumerate(self.lightList.GetItems()): handler = depot.getHandlerWithName(name) self.lightList.SetStringSelection(name, handler.getIsEnabled()) self.onLightSelect()
def takeBurst(self, frameCount=10): """ Use the internal triggering of the camera to take a burst of images Experimental """ cameraMask = 0 lightTimePairs = list() maxTime = 0 for handler, line in self.handlerToDigitalLine.items(): if handler.name in self.activeLights: maxTime = max(maxTime, handler.getExposureTime()) exposureTime = handler.getExposureTime() lightTimePairs.append((line, exposureTime)) maxTime = max(maxTime, exposureTime) for name, line in self.nameToDigitalLine.items(): if name in self.activeCameras: cameraMask += line handler = depot.getHandlerWithName(name) handler.setExposureTime(maxTime) sleep(5)
def executeRep(self, repNum): # Get all light sources that the microscope has. allLights = depot.getHandlersOfType(depot.LIGHT_TOGGLE) # getHandlersOfType returns an unordered set datatype. If we want to # index into allLights, we need to convert it to a list first. allLights = list(allLights) # Print the names of all light sources. for light in allLights: print(light.name) # Get all power controls for light sources. allLightPowers = depot.getHandlersOfType(depot.LIGHT_POWER) # Get all camera handlers that the microscope has, and filter it # down to the ones that are currently active. allCameras = depot.getHandlersOfType(depot.CAMERA) # Create a new empty list. activeCams = [] for camera in allCameras: if camera.getIsEnabled(): # Camera is enabled. activeCams.append(camera) # Get a specific light. led650 = depot.getHandlerWithName("650 LED") # Get a specific light's power control (ditto). led650power = depot.getHandlerWithName("650 LED power") # Set the output power to use for this light source, when it is active. led650power.setPower(2.5) # Set this light source to be continually exposing. led650.setExposing(True) # Wait for some time (1.5 seconds in this case). time.sleep(1.5) # Set this light source to stop continually exposing. led650.setExposing(False) # Get another light source. laser488 = depot.getHandlerWithName("488 L") # Set this light source to be enabled when we take images. # Note: for lasers, an AOM in the laser box that acts as a light # shutter is automatically adjusted when you enable/disable lights. # I don't know how well enabling multiple lasers simultaneously works. # Note: lasers, the DIA light source, and the EPI light source, are # mutually exclusive as they use different shutters and only one # shutter can be active at a time for some unknown reason. laser488.setEnabled(True) # Take images, using all current active camera views and light # sources; wait for the image (and time of acquisition) from the named # camera to be available. # Note: The light sources selected automatically use the emission # filter you have set in the UI. If multiple lights use the same # emission filter, then they will expose simultaneously (if possible). # Note: that if you try to wait for an image # that will never arrive (e.g. for the wrong camera name) then your # script will get stuck at this point. # Note: you must have at least one light source enabled for any # image to be taken! eventName = 'new image %s' % activeCams[0].name image, timestamp = events.executeAndWaitFor( eventName, cockpit.interfaces.imager.takeImage, shouldBlock=True) # Get the min, max, median, and standard deviation of the image imageMin = image.min() imageMax = image.max() imageMedian = numpy.median(image) imageStd = numpy.std(image) print("Image stats:", imageMin, imageMax, imageMedian, imageStd) # Some miscellaneous functions below. # Get the current stage position; positions are in microns. curX, curY, curZ = cockpit.interfaces.stageMover.getPosition() # Move to a new Z position, and wait until we arrive. cockpit.interfaces.stageMover.goToZ(curZ + 5, shouldBlock=True) # Move to a new XY position. # Note: the goToXY function expects a "tuple" for the position, # hence the extra parentheses (i.e. "goToXY(x, y)" is invalid; # "goToXY((x, y))" is correct). cockpit.interfaces.stageMover.goToXY((curX + 50, curY - 50), shouldBlock=True) # Get the device responsible for the dichroics and light sources lightsDevice = depot.getDevice(cockpit.devices.lights) # Set a new filter/dichroic for the lower turret. lightsDevice.setFilter(isFirstFilter=True, label="2-488 L") # Set a new filter/dichroic for the upper turret. lightsDevice.setFilter(isFirstFilter=False, label="6-600bp")
def executeRep(self, repNum): # Get all light sources that the microscope has. allLights = depot.getHandlersOfType(depot.LIGHT_TOGGLE) # getHandlersOfType returns an unordered set datatype. If we want to # index into allLights, we need to convert it to a list first. allLights = list(allLights) # Print the names of all light sources. for light in allLights: print(light.name) # Get all power controls for light sources. allLightPowers = depot.getHandlersOfType(depot.LIGHT_POWER) # Get all light source filters. allLightFilters = depot.getHandlersOfType(depot.LIGHT_FILTER) # Get all camera handlers that the microscope has, and filter it # down to the ones that are currently active. allCameras = depot.getHandlersOfType(depot.CAMERA) # Create a new empty list. activeCams = [] for camera in allCameras: if camera.getIsEnabled(): # Camera is enabled. activeCams.append(camera) # Get a specific light. deepstar405 = depot.getHandlerWithName("488 Deepstar") deepstar405power = depot.getHandlerWithName("488 Deepstar power") # Set the output power to use for this light source, when it is active. deepstar405power.setPower(15) # Get another light source. The "\n" in the name is a newline, which # was inserted (when this light source handler was created) to make # the light control button look nice. laser488 = depot.getHandlerWithName("488\nlight") # Set this light source to be enabled when we take images. laser488.setEnabled(True) # Take images, using all current active camera views and light # sources; wait for the image (and time of acquisition) from the named # camera to be available. # Note: that if you try to wait for an image # that will never arrive (e.g. for the wrong camera name) then your # script will get stuck at this point. eventName = 'new image %s' % activeCams[0].name image, timestamp = events.executeAndWaitFor( eventName, cockpit.interfaces.imager.takeImage, shouldBlock=True) # Get the min, max, median, and standard deviation of the image imageMin = image.min() imageMax = image.max() imageMedian = numpy.median(image) imageStd = numpy.std(image) print("Image stats:", imageMin, imageMax, imageMedian, imageStd) # Some miscellaneous functions below. # Get the current stage position; positions are in microns. curX, curY, curZ = cockpit.interfaces.stageMover.getPosition() # Move to a new Z position, and wait until we arrive. cockpit.interfaces.stageMover.goToZ(curZ + 5, shouldBlock=True) # Move to a new XY position. # Note: the goToXY function expects a "tuple" for the position, # hence the extra parentheses (i.e. "goToXY(x, y)" is invalid; # "goToXY((x, y))" is correct). cockpit.interfaces.stageMover.goToXY((curX + 50, curY - 50), shouldBlock=True)
def generateActions(self): table = actionTable.ActionTable() # Open all light sources for the duration of the experiment. # Normally the delay generator logic would do this for us. for cameras, exposures in self.exposureSettings: for light, exposureTime in exposures: table.addAction(0, light, True) shutter = depot.getHandlerWithName('488 shutter') delayGen = depot.getHandlerWithName('Delay generator trigger') curTime = 0 table.addAction(curTime, shutter, True) prevAltitude = None numZSlices = int(math.ceil(self.zHeight / self.sliceHeight)) for zIndex in range(numZSlices): # Move to the next position, then wait for the stage to # stabilize. zTarget = self.zStart + self.sliceHeight * zIndex motionTime, stabilizationTime = 0, 0 if prevAltitude is not None: motionTime, stabilizationTime = self.zPositioner.getMovementTime( prevAltitude, zTarget) table.addAction(curTime + motionTime, self.zPositioner, zTarget) curTime += motionTime + stabilizationTime prevAltitude = zTarget # Trigger the delay generator. Do it slightly *after* the trigger # of the cameras below, so that we ensure the first exposure, which # may be very brief, is fully-contained in a camera exposure. table.addToggle(curTime + decimal.Decimal('.5'), delayGen) # Trigger the cameras twice. Lazy; only allow one set of cameras. cameras = self.exposureSettings[0][0] for camera in cameras: table.addToggle(curTime, camera) table.addToggle(curTime + self.exposureDelay, camera) self.cameraToImageCount[camera] += 2 maxCamDelay = max( c.getTimeBetweenExposures(isExact=True) for c in cameras) # Wait for the exposure to complete and/or for the cameras to be # ready again. longExposureTime = self.exposureSettings[0][1][0][ 1] * self.exposureMultiplier curTime += self.exposureDelay + max( maxCamDelay, self.exposureDelay + longExposureTime) # Plus a little extra for the cameras to recover. # \todo This seems a bit excessive; why do we need to wait so # long for the Zyla to be ready? curTime += decimal.Decimal('10') # Hold the Z motion flat during the exposure. table.addAction(curTime, self.zPositioner, zTarget) # Close all light sources we opened at the start. # Normally the delay generator logic would do this for us. for cameras, exposures in self.exposureSettings: for light, exposureTime in exposures: table.addAction(curTime, light, False) # Move back to the start so we're ready for the next rep. motionTime, stabilizationTime = self.zPositioner.getMovementTime( self.zHeight, 0) curTime += motionTime table.addAction(curTime, self.zPositioner, 0) # Hold flat for the stabilization time, and any time needed for # the cameras to be ready. Only needed if we're doing multiple # reps, so we can proceed immediately to the next one. cameraReadyTime = 0 if self.numReps > 1: for cameras, lightTimePairs in self.exposureSettings: for camera in cameras: cameraReadyTime = max( cameraReadyTime, self.getTimeWhenCameraCanExpose(table, camera)) table.addAction(max(curTime + stabilizationTime, cameraReadyTime), self.zPositioner, 0) return table