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
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)
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