Esempio n. 1
0
def measure_spot_intensities(
    data_image: ImageStack,
    spot_attributes: SpotAttributes,
    measurement_function: Callable[[Sequence], Number],
    radius_is_gyration: bool = False,
) -> IntensityTable:
    """given spots found from a reference image, find those spots across a data_image

    Parameters
    ----------
    data_image : ImageStack
        ImageStack containing multiple volumes for which spots' intensities must be calculated
    spot_attributes : pd.Dataframe
        Locations and radii of spots
    measurement_function : Callable[[Sequence], Number])
        Function to apply over the spot volumes to identify the intensity (e.g. max, mean, ...)
    radius_is_gyration : bool
        if True, indicates that the radius corresponds to radius of gyration, which is a function of
        spot intensity, but typically is a smaller unit than the sigma generated by blob_log.
        In this case, the spot's bounding box is rounded up instead of down when measuring
        intensity. (default False)

    Returns
    -------
    IntensityTable :
        3d tensor of (spot, channel, round) information for each coded spot

    """

    # determine the shape of the intensity table
    n_ch = data_image.shape[Axes.CH]
    n_round = data_image.shape[Axes.ROUND]

    # construct the empty intensity table
    intensity_table = IntensityTable.empty_intensity_table(
        spot_attributes=spot_attributes,
        n_ch=n_ch,
        n_round=n_round,
    )

    # if no spots were detected, return the empty IntensityTable
    if intensity_table.sizes[Features.AXIS] == 0:
        return intensity_table

    # fill the intensity table
    indices = product(range(n_ch), range(n_round))
    for c, r in indices:
        image, _ = data_image.get_slice({Axes.CH: c, Axes.ROUND: r})
        blob_intensities: pd.Series = measure_spot_intensity(
            image,
            spot_attributes,
            measurement_function,
            radius_is_gyration=radius_is_gyration)
        intensity_table[:, c, r] = blob_intensities

    return intensity_table
Esempio n. 2
0
def verify_stack_data(
    stack: ImageStack,
    selectors: Mapping[Axes, Union[int, slice]],
    expected_data: np.ndarray,
) -> Tuple[np.ndarray, Sequence[Axes]]:
    """Given an imagestack and a set of selectors, verify that the data referred to by the selectors
    matches the expected data.
    """
    tile_data, axes = stack.get_slice(selectors)
    assert np.array_equal(tile_data, expected_data)

    return tile_data, axes
Esempio n. 3
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
Esempio n. 4
0
def verify_stack_fill(
    stack: ImageStack,
    selectors: Mapping[Axes, Union[int, slice]],
    expected_fill_value: Number,
) -> Tuple[np.ndarray, Sequence[Axes]]:
    """Given an imagestack and a set of selectors, verify that the data referred to by the selectors
    matches an expected fill value.
    """
    tile_data, axes = stack.get_slice(selectors)
    expected_data = np.full(tile_data.shape, expected_fill_value, np.float32)
    assert np.array_equal(tile_data, expected_data)

    return tile_data, axes
Esempio n. 5
0
    def run(self,
            stack: ImageStack,
            transforms_list: TransformsList,
            in_place: bool = False,
            verbose: bool = False,
            *args,
            **kwargs) -> ImageStack:
        """Applies a list of transformations to an ImageStack

        Parameters
        ----------
        stack : ImageStack
            Stack to be transformed.
        transforms_list: TransformsList
            The list of transform objects to apply to the ImageStack.
        in_place : bool
            if True, process ImageStack in-place, otherwise return a new stack
        verbose : bool
            if True, report on transformation progress (default = False)

        Returns
        -------
        ImageStack :
            If in-place is False, return the results of the transforms as a new stack.
            Otherwise return the original stack.
        """
        if not in_place:
            # create a copy of the ImageStack, call apply on that stack with in_place=True
            image_stack = deepcopy(stack)
            return self.run(image_stack,
                            transforms_list,
                            in_place=True,
                            **kwargs)
        if verbose and StarfishConfig().verbose:
            transforms_list.transforms = tqdm(transforms_list.transforms)
        all_axes = {Axes.ROUND, Axes.CH, Axes.ZPLANE}
        for selector, _, transformation_object in transforms_list.transforms:
            other_axes = all_axes - set(selector.keys())
            # iterate through remaining axes
            for axes in stack._iter_axes(other_axes):
                # combine all axes data to select one tile
                selector.update(axes)  # type: ignore
                selected_image, _ = stack.get_slice(selector)
                warped_image = warp(selected_image, transformation_object,
                                    **kwargs).astype(np.float32)
                stack.set_slice(selector, warped_image)
        return stack