def run(self, image: ImageStack, in_place: bool = False) -> Optional[ImageStack]: """Register an ImageStack against a reference image. Parameters ---------- image : ImageStack The stack to be registered in_place : bool If false, return a new registered stack. Else, register in-place (default False) Returns ------- """ if not in_place: image = deepcopy(image) # TODO: (ambrosejcarr) is this the appropriate way of dealing with Z in registration? mp = image.max_proj(Axes.CH, Axes.ZPLANE) mp_numpy = mp._squeezed_numpy(Axes.CH, Axes.ZPLANE) reference_image_mp = self.reference_stack.max_proj( Axes.ROUND, Axes.CH, Axes.ZPLANE) reference_image_numpy = reference_image_mp._squeezed_numpy( Axes.ROUND, Axes.CH, Axes.ZPLANE) for r in image.axis_labels(Axes.ROUND): # compute shift between maximum projection (across channels) and dots, for each round # TODO: make the max projection array ignorant of axes ordering. shift, error = compute_shift(mp_numpy[r, :, :], reference_image_numpy, self.upsampling) print(f"For round: {r}, Shift: {shift}, Error: {error}") for c in image.axis_labels(Axes.CH): for z in image.axis_labels(Axes.ZPLANE): # apply shift to all zplanes, channels, and imaging rounds selector = {Axes.ROUND: r, Axes.CH: c, Axes.ZPLANE: z} data, axes = image.get_slice(selector=selector) assert len(axes) == 0 result = shift_im(data, shift) result = preserve_float_range(result) image.set_slice(selector=selector, data=result) if not in_place: return image return None
def run( self, stack: ImageStack, in_place: bool=False, verbose=False, n_processes: Optional[int]=None, *args, ) -> ImageStack: """Perform filtering of an image stack Parameters ---------- stack : ImageStack Stack to be filtered. in_place : bool if True, process ImageStack in-place, otherwise return a new stack verbose : bool if True, report on the percentage completed during processing (default = False) n_processes : Optional[int]: None Not implemented. Number of processes to use when applying filter. Returns ------- ImageStack : If in-place is False, return the results of filter as a new stack. Otherwise return the original stack. """ # The default is False, so even if code requests True require config to be True as well verbose = verbose and StarfishConfig().verbose channels_per_round = stack._data.groupby(Axes.ROUND.value) channels_per_round = tqdm(channels_per_round) if verbose else channels_per_round if not in_place: new_stack = deepcopy(stack) return self.run(new_stack, in_place=True) # compute channel magnitude mask for r, dat in channels_per_round: # nervous about how xarray orders dimensions so i put this here explicitly .... dat = dat.transpose(Axes.CH.value, Axes.ZPLANE.value, Axes.Y.value, Axes.X.value ) # ... to account for this line taking the norm across axis 0, or the channel axis ch_magnitude = np.linalg.norm(dat, ord=2, axis=0) magnitude_mask = ch_magnitude >= self.thresh # apply mask and optionally, normalize by channel magnitude for c in stack.axis_labels(Axes.CH): ind = {Axes.ROUND.value: r, Axes.CH.value: c} stack._data[ind] = stack._data[ind] * magnitude_mask if self.normalize: stack._data[ind] = np.divide(stack._data[ind], ch_magnitude, where=magnitude_mask ) return stack
def run(self, stack: ImageStack, verbose: bool = False, *args) -> TransformsList: """ Iterate over the given axes of an ImageStack and learn the Similarity transform based off the reference_stack passed into :py:class:`Translation`'s constructor. Only supports 2d data. Parameters ---------- stack : ImageStack Stack to calculate the transforms on. verbose : bool if True, report on transformation progress (default = False) Returns ------- List[Tuple[Mapping[Axes, int], SimilarityTransform]] : A list of tuples containing axes of the Imagestack and associated transform to apply. """ transforms = TransformsList() reference_image = np.squeeze(self.reference_stack.xarray) for a in stack.axis_labels(self.axes): target_image = np.squeeze(stack.sel({self.axes: a}).xarray) if len(target_image.shape) != 2: raise ValueError( f"Only axes: {self.axes.value} can have a length > 1, " f"please use the MaxProj filter.") shift, error, phasediff = register_translation( src_image=target_image, target_image=reference_image, upsample_factor=self.upsampling) if verbose: print(f"For {self.axes}: {a}, Shift: {shift}, Error: {error}") selectors = {self.axes: a} # reverse shift because SimilarityTransform stores in y,x format shift = shift[::-1] transforms.append(selectors, TransformType.SIMILARITY, SimilarityTransform(translation=shift)) return transforms