Example #1
0
    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
Example #2
0
    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
Example #3
0
    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