def __init__(self, name, image): """ Note: parameters are different from the base class. image (DataArray of shape (111)YX): raw data. The metadata should contain at least MD_POS and MD_PIXEL_SIZE. It should also contain MD_IN_WL and MD_OUT_WL. """ # Note: it will update the image, and changing the tint will do it again super(StaticFluoStream, self).__init__(name, image) # Wavelengths try: exc_range = image.metadata[model.MD_IN_WL] self.excitation = VigilantAttribute(exc_range, unit="m", readonly=True) except KeyError: logging.warning("No excitation wavelength for fluorescence stream") default_tint = (0, 255, 0) # green is most typical try: em_range = image.metadata[model.MD_OUT_WL] if isinstance(em_range, basestring): unit = None else: unit = "m" default_tint = conversion.wave2rgb(numpy.mean(em_range)) self.emission = VigilantAttribute(em_range, unit=unit, readonly=True) except KeyError: logging.warning("No emission wavelength for fluorescence stream") # colouration of the image tint = image.metadata.get(model.MD_USER_TINT, default_tint) self.tint.value = tint
def __init__(self, name, image): """ Note: parameters are different from the base class. image (DataArray of shape (111)YX): raw data. The metadata should contain at least MD_POS and MD_PIXEL_SIZE. It should also contain MD_IN_WL and MD_OUT_WL. """ # Wavelengths try: exc_range = image.metadata[model.MD_IN_WL] self.excitation = VigilantAttribute(exc_range, unit="m", readonly=True) except KeyError: logging.warning("No excitation wavelength for fluorescence stream") try: em_range = image.metadata[model.MD_OUT_WL] self.emission = VigilantAttribute(em_range, unit="m", readonly=True) default_tint = conversion.wave2rgb(numpy.mean(em_range)) except KeyError: logging.warning("No emission wavelength for fluorescence stream") default_tint = (0, 255, 0) # green is most typical # colouration of the image tint = image.metadata.get(model.MD_USER_TINT, default_tint) self.tint = model.ListVA(tint, unit="RGB") # 3-tuple R,G,B self.tint.subscribe(self.onTint) # Do it at the end, as it forces it the update of the image StaticStream.__init__(self, name, image)
def __init__(self, name, raw): """ Note: parameters are different from the base class. raw (DataArray of shape (111)YX): raw data. The metadata should contain at least MD_POS and MD_PIXEL_SIZE. It should also contain MD_IN_WL and MD_OUT_WL. """ # Note: it will update the image, and changing the tint will do it again super(StaticFluoStream, self).__init__(name, raw) # Wavelengths try: exc_range = raw.metadata[model.MD_IN_WL] self.excitation = VigilantAttribute(exc_range, unit="m", readonly=True) except KeyError: logging.warning("No excitation wavelength for fluorescence stream") default_tint = (0, 255, 0) # green is most typical try: em_range = raw.metadata[model.MD_OUT_WL] if isinstance(em_range, basestring): unit = None else: unit = "m" default_tint = conversion.wave2rgb(numpy.mean(em_range)) self.emission = VigilantAttribute(em_range, unit=unit, readonly=True) except KeyError: logging.warning("No emission wavelength for fluorescence stream") # colouration of the image tint = raw.metadata.get(model.MD_USER_TINT, default_tint) self.tint.value = tint
def test_wave2rgb(self): # (input) (expected output) values = [(200.51513e-9, (255, 0, 255)), (350e-9, (255, 0, 255)), (490e-9, (0, 255, 255)), (700e-9, (255, 0, 0)), (900.5e-9, (255, 0, 0)), ] for (i, eo) in values: o = conversion.wave2rgb(i) self.assertEquals(o, eo, u"%f nm -> %s should be %s" % (i * 1e9, o, eo))
def __init__(self, name): Stream.__init__(self, name, None, None, None) #pylint: disable=W0233 # For imitating also a FluoStream self.excitation = model.FloatContinuous(488e-9, range=[200e-9, 1000e-9], unit="m") self.emission = model.FloatContinuous(507e-9, range=[200e-9, 1000e-9], unit="m") defaultTint = conversion.wave2rgb(self.emission.value) self.tint = model.VigilantAttribute(defaultTint, unit="RGB") self.histogram._edges = (0, 0) self._calibrated = None
def __init__(self, name): Stream.__init__(self, name, None, None, None) #pylint: disable=W0233 # For imitating also a FluoStream self.excitation = model.FloatContinuous( 488e-9, range=[200e-9, 1000e-9], unit="m") self.emission = model.FloatContinuous( 507e-9, range=[200e-9, 1000e-9], unit="m") defaultTint = conversion.wave2rgb(self.emission.value) self.tint = model.VigilantAttribute(defaultTint, unit="RGB") self.histogram._edges = (0, 0) self._calibrated = None
def __init__(self, name): Stream.__init__(self, name, None, None, None) # For imitating a FluoStream self.excitation = model.VAEnumerated( (4.2e-07, 4.3e-07, 4.38e-07, 4.45e-07, 4.55e-07), # multiple spectra choices={(4.2e-07, 4.3e-07, 4.38e-07, 4.45e-07, 4.55e-07), (3.75e-07, 3.9e-07, 4e-07, 4.02e-07, 4.05e-07), (5.65e-07, 5.7e-07, 5.75e-07, 5.8e-07, 5.95e-07), (5.25e-07, 5.4e-07, 5.5e-07, 5.55e-07, 5.6e-07), (4.95e-07, 5.05e-07, 5.13e-07, 5.2e-07, 5.3e-07)}, unit="m") self.emission = model.VAEnumerated( (500e-9, 520e-9), # one (fixed) multi-band choices={(100e-9, 150e-9), (500e-9, 520e-9), (600e-9, 650e-9)}, unit="m") default_tint = conversion.wave2rgb(488e-9) self.tint = model.VigilantAttribute(default_tint, unit="RGB") self.histogram._edges = (0, 0)
def __init__(self, name, detector, dataflow, emitter, em_filter): """ name (string): user-friendly name of this stream detector (Detector): the detector which has the dataflow dataflow (Dataflow): the dataflow from which to get the data emitter (Light): the HwComponent to modify the light excitation filter (Filter): the HwComponent to modify the emission light filtering """ CameraStream.__init__(self, name, detector, dataflow, emitter) self._em_filter = em_filter # Emission and excitation are based on the hardware capacities. # For excitation, compared to the hardware, only one band at a time can # be selected. The difficulty comes to pick the default value. The best # would be to use the current hardware value, but if the light is off # there is no default value. In that case, we pick the emission value # and try to pick a compatible excitation value: the first excitation # wavelength below the emission. However, the emission value might also # be difficult to know if there is a multi-band filter. In that case we # just pick the lowest value. # TODO: once the streams have their own version of the hardware settings # and in particular light.power, it should be possible to turn off the # light just by stopping the power, and so leaving the emissions as is. em_choices = em_filter.axes["band"].choices.copy() # convert any list into tuple, as lists cannot be put in a set for k, v in em_choices.items(): em_choices[k] = conversion.ensureTuple(v) # invert the dict, to directly convert the emission to the position value self._emission_to_idx = dict((v, k) for k, v in em_choices.items()) cur_pos = em_filter.position.value["band"] current_em = em_choices[cur_pos] if isinstance(current_em[0], collections.Iterable): # if multiband => pick the first one em_band = current_em[0] else: em_band = current_em center_em = fluo.get_center(em_band) exc_choices = set(emitter.spectra.value) current_exc = self._get_current_excitation() if current_exc is None: # pick the closest below the current emission current_exc = min(exc_choices, key=lambda b: b[2]) # default to the smallest for b in exc_choices: # Works because exc_choices only contains 5-float tuples if (b[2] < center_em and center_em - b[2] < center_em - current_exc[2]): current_exc = b logging.debug("Guessed excitation is %s, based on emission %s", current_exc, current_em) self.excitation = model.VAEnumerated(current_exc, choices=exc_choices, unit="m") self.excitation.subscribe(self.onExcitation) # The wavelength band on the out path (set when emission changes) self.emission = model.VAEnumerated(current_em, choices=set(em_choices.values()), unit="m") self.emission.subscribe(self.onEmission) # colouration of the image default_tint = conversion.wave2rgb(center_em) self.tint = model.ListVA(default_tint, unit="RGB") # 3-tuple R,G,B self.tint.subscribe(self.onTint)
def __init__(self, name, detector, dataflow, emitter, em_filter, **kwargs): """ name (string): user-friendly name of this stream detector (Detector): the detector which has the dataflow dataflow (Dataflow): the dataflow from which to get the data emitter (Light): the HwComponent to modify the light excitation em_filter (Filter): the HwComponent to modify the emission light filtering """ super(FluoStream, self).__init__(name, detector, dataflow, emitter, **kwargs) self._em_filter = em_filter # Emission and excitation are based on the hardware capacities. # For excitation, compared to the hardware, only one band at a time can # be selected. The difficulty comes to pick the default value. The best # would be to use the current hardware value, but if the light is off # there is no default value. In that case, we pick the emission value # and try to pick a compatible excitation value: the first excitation # wavelength below the emission. However, the emission value might also # be difficult to know if there is a multi-band filter. In that case we # just pick the lowest value. # TODO: once the streams have their own version of the hardware settings # and in particular light.power, it should be possible to turn off the # light just by stopping the power, and so leaving the emissions as is. em_choices = em_filter.axes["band"].choices.copy() # convert any list into tuple, as lists cannot be put in a set for k, v in em_choices.items(): em_choices[k] = conversion.ensure_tuple(v) # invert the dict, to directly convert the emission to the position value self._emission_to_idx = {v: k for k, v in em_choices.items()} cur_pos = em_filter.position.value["band"] current_em = em_choices[cur_pos] if isinstance(current_em[0], collections.Iterable): # if multiband => pick the first one em_band = current_em[0] else: em_band = current_em center_em = fluo.get_center(em_band) exc_choices = set(emitter.spectra.value) current_exc = self._get_current_excitation() if current_exc is None: # pick the closest below the current emission current_exc = min(exc_choices, key=lambda b: b[2]) # default to the smallest for b in exc_choices: # Works because exc_choices only contains 5-float tuples if (b[2] < center_em and center_em - b[2] < center_em - current_exc[2]): current_exc = b logging.debug("Guessed excitation is %s, based on emission %s", current_exc, current_em) self.excitation = model.VAEnumerated(current_exc, choices=exc_choices, unit="m") self.excitation.subscribe(self.onExcitation) # The wavelength band on the out path (set when emission changes) self.emission = model.VAEnumerated(current_em, choices=set(em_choices.values()), unit="m") self.emission.subscribe(self.onEmission) # colouration of the image self.tint.value = conversion.wave2rgb(center_em)
def __init__(self, name, detector, dataflow, emitter, em_filter, **kwargs): """ name (string): user-friendly name of this stream detector (Detector): the detector which has the dataflow dataflow (Dataflow): the dataflow from which to get the data emitter (Light): the HwComponent to modify the light excitation em_filter (Filter or None): the HwComponent to modify the emission light filtering. If None, it will assume it's fixed and indicated on the MD_OUT_WL of the detector. """ if "acq_type" not in kwargs: kwargs["acq_type"] = model.MD_AT_FLUO super(FluoStream, self).__init__(name, detector, dataflow, emitter, **kwargs) self._em_filter = em_filter # Emission and excitation are based on the hardware capacities. # For excitation, contrary to the hardware, only one band at a time can # be selected. The difficulty comes to pick the default value. We try # to use the current hardware value, but if the light is off there is no # default value. In that case, we pick the emission value that matches # best the excitation value. if em_filter: em_choices = em_filter.axes["band"].choices.copy() # convert any list into tuple, as lists cannot be put in a set for k, v in em_choices.items(): em_choices[k] = conversion.ensure_tuple(v) # invert the dict, to directly convert the emission to the position value self._emission_to_idx = {v: k for k, v in em_choices.items()} cur_pos = em_filter.position.value["band"] current_em = em_choices[cur_pos] else: # TODO: is that a good idea? On a system with multiple detectors # (eg, confocal with several photo-detectors), should we just have a # filter per detector, instead of having this "shortcut"? try: current_em = detector.getMetadata()[model.MD_OUT_WL] except KeyError: raise ValueError("No em_filter passed, and detector has not MD_OUT_WL") current_em = conversion.ensure_tuple(current_em) em_choices = {None: current_em} # No ._emission_to_idx center_em = fluo.get_one_center(current_em) exc_choices = set(emitter.spectra.value) current_exc = self._get_current_excitation() if current_exc is None: current_exc = fluo.get_one_band_ex(exc_choices, current_em) logging.debug("Guessed excitation is %s, based on emission %s", current_exc, current_em) self.excitation = model.VAEnumerated(current_exc, choices=exc_choices, unit="m") self.excitation.subscribe(self.onExcitation) # The wavelength band on the out path (set when emission changes) self.emission = model.VAEnumerated(current_em, choices=set(em_choices.values()), unit="m") self.emission.subscribe(self.onEmission) # colouration of the image self.tint.value = conversion.wave2rgb(center_em)