Exemple #1
0
def rescale_stack(tile, stack, scale_factor):
    """Restore mean intensity of z-stack

    This is transformation used in the Nolanlab code to rescale means
    of deconvolution results back to the original (they're not usually
    off by much though).  scale_factor is then a tunable way to lower or
    raise the intensity values so that when clipping to uint type (with
    no scaling) there is less saturation.
    """
    mean_ratio = tile.mean() / np_utils.arr_to_uint(stack, tile.dtype).mean()
    logger.debug(
        'Mean ratio of original stack to deconvolved stack = {}'.format(
            mean_ratio))
    return stack * (mean_ratio * scale_factor), mean_ratio
Exemple #2
0
    def _run(self, tile, **kwargs):
        if not np.issubdtype(tile.dtype, np.unsignedinteger):
            raise ValueError('Only unsigned integer images supported; '
                             'type given = {}'.format(tile.dtype))

        # Tile should have shape (cycles, z, channel, height, width)
        ncyc, nz, nch, nh, nw = tile.shape

        # Ensure that given tile has same number of channels as required in configuration
        # since PSF generation is specific for each channel
        if nch != self.config.n_channels_per_cycle:
            raise AssertionError(
                'Given tile with shape {} ({} channels) does not have expected number of channels {}'
                .format(tile.shape, nch, self.config.n_channels_per_cycle))

        img_cyc = []
        for icyc in range(ncyc):
            img_ch = []
            for ich in range(nch):
                img = tile[icyc, :, ich, :, :]

                # Skip deconvolution if channel was configured to be ignored
                if self.channels is not None and ich not in self.channels:
                    img_ch.append(img)
                    continue

                acq = fd_data.Acquisition(img, kernel=self.psfs[ich])
                logger.debug(
                    'Running deconvolution for cycle {}, channel {} [dtype = {}]'
                    .format(icyc, ich, acq.data.dtype))
                res = self.algo.run(acq,
                                    self.n_iter,
                                    session_config=get_tf_config(self)).data

                # Restore mean intensity if a scale factor was given
                if self.scale_factor is not None:
                    res, mean_ratio = rescale_stack(acq.data, res,
                                                    self.scale_factor)
                    self.record({
                        'mean_ratio': mean_ratio,
                        'cycle': icyc,
                        'channel': ich
                    })

                # Clip float32 and convert to type of original image (i.e. w/ no scaling)
                res = np_utils.arr_to_uint(res, acq.data.dtype)

                img_ch.append(res)
            img_cyc.append(np.stack(img_ch, 1))
        return np.stack(img_cyc, 0)
Exemple #3
0
    def _run(self, tile, **kwargs):
        if not np.issubdtype(tile.dtype, np.unsignedinteger):
            raise ValueError('Only unsigned integer images supported; '
                             'type given = {}'.format(tile.dtype))

        # Tile should have shape (cycles, z, channel, height, width)
        dims = self.config.tile_dims
        if dims != tile.shape:
            raise AssertionError(
                'Given tile with shape {} does not match expected shape {}'.
                format(tile.shape, dims))
        ncyc, nz, nch, nh, nw = dims

        img_cyc = []
        for icyc in range(ncyc):
            img_ch = []
            for ich in range(nch):
                acq = fd_data.Acquisition(tile[icyc, :, ich, :, :],
                                          kernel=self.psfs[ich])
                logger.debug(
                    'Running deconvolution for cycle {}, channel {} [dtype = {}]'
                    .format(icyc, ich, acq.data.dtype))
                res = self.algo.run(acq,
                                    self.n_iter,
                                    session_config=get_tf_config(self)).data

                # Restore mean intensity if a scale factor was given
                if self.scale_factor is not None:
                    res, mean_ratio = rescale_stack(acq.data, res,
                                                    self.scale_factor)
                    self.record({
                        'mean_ratio': mean_ratio,
                        'cycle': icyc,
                        'channel': ich
                    })

                # Clip float32 and convert to type of original image (i.e. w/ no scaling)
                res = np_utils.arr_to_uint(res, acq.data.dtype)

                img_ch.append(res)
            img_cyc.append(np.stack(img_ch, 1))
        return np.stack(img_cyc, 0)
    def _run(self, tile, **kwargs):
        # Compute drift between reference cycle and all others
        logger.info('Calculating drift translations')
        translations = self._get_translations(tile)

        # If there is only one cycle, then drift compensation is not possible so return the given tile as-is
        if self.config.n_cycles < 2:
            logger.debug(
                'Experiment has less than 2 cycles so drift compensation operation will result in no changes'
            )
            return tile

        # Apply translations and convert back to original type from float32
        logger.info('Applying drift translations')
        res = self._apply_translations(tile, translations)
        res = np_utils.arr_to_uint(res, tile.dtype)

        # Validate shape of result
        if res.shape != tile.shape:
            raise AssertionError(
                'Tile shape after drift compensation ({}) does not match input shape ({})'
                .format(res.shape, tile.shape))
        return res