Esempio n. 1
0
def test_binarize_non_3d(num_rounds, num_chs, num_zplanes=4, ysize=5, xsize=6):
    data = np.linspace(0,
                       1,
                       num_rounds * num_chs * num_zplanes * ysize * xsize,
                       dtype=np.float32)
    data = data.reshape((num_rounds, num_chs, num_zplanes, ysize, xsize))

    imagestack = ImageStack.from_numpy(data)
    binarizer = ThresholdBinarize(0.0)

    with pytest.raises(ValueError):
        binarizer.run(imagestack)
def jitter_code() -> ImageStack:
    """this code has some minor jitter <= 3px at the most distant point"""
    img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)

    # code 1
    img[0, 0, 5, 35, 35] = 10
    img[1, 1, 5, 34, 35] = 10
    img[2, 0, 6, 35, 33] = 10

    # blur points
    gaussian_filter(img, (0, 0, 0.5, 1.5, 1.5), output=img)

    return ImageStack.from_numpy(img)
def traversing_code() -> ImageStack:
    """this code walks in a sequential direction, and should only be detectable from some anchors"""
    img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)

    # code 1
    img[0, 0, 5, 35, 35] = 10
    img[1, 1, 5, 32, 32] = 10
    img[2, 0, 5, 29, 29] = 10

    # blur points
    gaussian_filter(img, (0, 0, 0.5, 1.5, 1.5), output=img)

    return ImageStack.from_numpy(img)
Esempio n. 4
0
def make_expected_image_stack():
    '''
        Make the expected image stack result
    '''

    base_calls = np.array(
        [[[[[0, 0], [0, 0]]], [[[0, 0.755929], [0, 0]]],
          [[[0, 0], [0.755929, 0]]], [[[0, 0], [0, 0.755929]]]]],
        dtype='float32')

    expected_stack = ImageStack.from_numpy(base_calls)

    return expected_stack
Esempio n. 5
0
def test_intensity_table_concatenation():
    """create two IntensityTables and assert that they are being concatenated properly."""

    r, c, z, y, x = 3, 3, 2, 2, 5
    data = np.zeros(180, dtype=np.float32).reshape(r, c, z, y, x)
    image_stack = ImageStack.from_numpy(data)
    intensities = IntensityTable.from_image_stack(image_stack)

    intensities2 = intensities.copy()

    original_shape = intensities.shape

    expected_shape = list(original_shape)
    expected_shape[0] *= 2  # only features is concatenated
    assert np.array_equal(
        concatenate([intensities, intensities2]).shape, expected_shape)

    # slice out a single channel and round from both experiments, such that the data no longer match
    # across all dimensions but the concatenation dimension. The resulting structure should be
    # 2 (r) * 2 (c) * 5 (z), 2, 2 = 40, 2, 2
    i1 = intensities.where(np.logical_and(intensities.r == 0,
                                          intensities.c == 0),
                           drop=True)
    i2 = intensities.where(np.logical_and(intensities.r == 1,
                                          intensities.c == 1),
                           drop=True)
    expected_shape = (i1.shape[0] + i2.shape[0], 2, 2)
    result = concatenate([i1, i2])

    assert expected_shape == result.shape

    # slice a larger r value for second array, however, there are still only two values, so
    # shape should be 40, 2, 2
    i3 = intensities.where(np.logical_and(intensities.r == 2,
                                          intensities.c == 1),
                           drop=True)
    expected_shape = (i1.shape[0] + i3.shape[0], 2, 2)
    result = concatenate([i1, i3])

    assert expected_shape == result.shape

    # slice out z in addition to reduce the total feature number by 1/2
    i4 = intensities.where(np.logical_and(intensities.r == 0,
                                          intensities.z == 1),
                           drop=True)
    expected_shape = (i1.shape[0] + i4.shape[0], 1, 3)
    result = concatenate([i1, i4])

    assert expected_shape == result.shape
Esempio n. 6
0
def test_from_fiji_roi_set():
    # set up empty dapi imagestack of correct size
    fake_dapi = ImageStack.from_numpy(array=np.zeros(shape=(1, 1, 1, 2048,
                                                            2048)))
    cwd = os.path.dirname(__file__)
    file_path = os.path.join(cwd, "RoiSet.zip")

    # load test roi_set.zip
    masks = BinaryMaskCollection.from_fiji_roi_set(file_path, fake_dapi)

    # check data and offsets set correctly
    assert len(masks) == 4
    assert masks._masks[0].offsets == (782, 760)
    assert masks._masks[1].offsets == (234, 680)
    assert masks._masks[2].offsets == (10, 980)
    assert masks._masks[3].offsets == (16, 768)
def test_lmpf_uniform_peak():
    data_array = np.zeros(shape=(1, 1, 1, 100, 100), dtype=np.float32)
    data_array[0, 0, 0, 45:55, 45:55] = 1
    imagestack = ImageStack.from_numpy(data_array)

    # standard local max peak finder, should find spots for all the evenly illuminated pixels.
    lmpf_no_kwarg = FindSpots.LocalMaxPeakFinder(1, 1, 1, sys.maxsize)
    peaks = lmpf_no_kwarg.run(imagestack)
    results_no_kwarg = peaks[{Axes.ROUND: 0, Axes.CH: 0}]
    assert len(results_no_kwarg.spot_attrs.data) == 100

    # local max peak finder, capped at one peak per label.
    lmpf_kwarg = FindSpots.LocalMaxPeakFinder(1, 1, 1, sys.maxsize, num_peaks_per_label=1)
    peaks = lmpf_kwarg.run(imagestack)
    results_kwarg = peaks[{Axes.ROUND: 0, Axes.CH: 0}]
    assert len(results_kwarg.spot_attrs.data) == 1
Esempio n. 8
0
def make_image_stack():
    """Make a test ImageStack."""

    # Make the test image
    test = np.ones((2, 4, 1, 2, 2), dtype='float32') * 0.1

    x = [0, 0, 1, 1]
    y = [0, 1, 0, 1]

    for i in range(4):
        test[0, i, 0, x[i], y[i]] = 1
    test[0, 0, 0, 0, 0] = 0.75

    # Make the ImageStack
    test_stack = ImageStack.from_numpy(test)

    return test_stack
Esempio n. 9
0
def test_imagestack_deepcopy(nitems: int=10) -> None:
    """
    Instantiate an :py:class:`ImageStack` and deepcopy it.  Worker processes reconstitute a numpy
    array from the buffer and attempts to writes to the numpy array.  Writes in the worker process
    should be visible in the parent process.
    """
    shape = (nitems, 3, 4, 5, 6)
    dtype = np.float32
    source = np.zeros(shape, dtype=np.float32)
    imagestack = ImageStack.from_numpy(source)
    imagestack_copy = copy.deepcopy(imagestack)
    _start_process_to_test_shmem(
        array_holder=imagestack_copy._data._backing_mp_array,
        decoder=partial(_decode_imagestack_array_to_numpy_array, shape, dtype),
        nitems=nitems)
    for ix in range(nitems):
        assert (imagestack.xarray[ix] == 0).all()
        assert np.allclose(imagestack_copy.xarray[ix], ix)
def two_perfect_codes() -> ImageStack:
    """this code has no jitter"""
    img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)

    # code 1
    img[0, 0, 5, 20, 35] = 10
    img[1, 1, 5, 20, 35] = 10
    img[2, 0, 5, 20, 35] = 10

    # code 1
    img[0, 0, 5, 40, 45] = 10
    img[1, 1, 5, 40, 45] = 10
    img[2, 0, 5, 40, 45] = 10

    # blur points
    gaussian_filter(img, (0, 0, 0.5, 1.5, 1.5), output=img)

    return ImageStack.from_numpy(img)
def test_intensity_table_serialization():
    """
    Test that an IntensityTable can be saved to disk, and that when it is reloaded, the data is
    unchanged
    """

    # create an IntensityTable
    data = np.zeros(100, dtype=np.float32).reshape(1, 5, 2, 2, 5)
    image_stack = ImageStack.from_numpy(data)
    intensities = IntensityTable.from_image_stack(image_stack)

    # dump it to disk
    tempdir = tempfile.mkdtemp()
    filename = os.path.join(tempdir, 'test.nc')
    intensities.to_netcdf(filename)

    # verify the data has not changed
    loaded = intensities.open_netcdf(filename)
    assert intensities.equals(loaded)
Esempio n. 12
0
def make_expected_image_stack(func):
    '''
        Make the expected image stack result
    '''

    if func == 'max':
        reduced = np.array(
            [[[[[0.75, 0.1],
                [0.1, 0.1]]],
                [[[0.1, 1],
                  [0.1, 0.1]]],
                [[[0.1, 0.1],
                  [1, 0.1]]],
                [[[0.1, 0.1],
                  [0.1, 1]]]]], dtype='float32'
        )
    elif func == 'mean':
        reduced = np.array(
            [[[[[0.425, 0.1],
              [0.1, 0.1]]],
              [[[0.1, 0.55],
                [0.1, 0.1]]],
              [[[0.1, 0.1],
                [0.55, 0.1]]],
              [[[0.1, 0.1],
                [0.1, 0.55]]]]], dtype='float32'
        )
    elif func == 'sum':
        reduced = np.array(
            [[[[[0.85, 0.2],
              [0.2, 0.2]]],
              [[[0.2, 1],
                [0.2, 0.2]]],
              [[[0.2, 0.2],
                [1, 0.2]]],
              [[[0.2, 0.2],
                [0.2, 1]]]]], dtype='float32'
        )

    expected_stack = ImageStack.from_numpy(reduced)

    return expected_stack
def multiple_possible_neighbors() -> ImageStack:
    """this image is intended to be tested with anchor_round in {0, 1}, last round has more spots"""
    img = np.zeros((3, 2, 20, 50, 50), dtype=np.float32)

    # round 1
    img[0, 0, 5, 20, 40] = 10
    img[0, 0, 5, 40, 20] = 10

    # round 2
    img[1, 1, 5, 20, 40] = 10
    img[1, 1, 5, 40, 20] = 10

    # round 3
    img[2, 0, 5, 20, 40] = 10
    img[2, 0, 5, 35, 35] = 10
    img[2, 0, 5, 40, 20] = 10

    # blur points
    gaussian_filter(img, (0, 0, 0.5, 1.5, 1.5), output=img)

    return ImageStack.from_numpy(img)
Esempio n. 14
0
def test_to_mermaid_dataframe():
    """
    Creates a basic IntensityTable from an ImageStack and verifies that it can be dumped to disk
    as a DataFrame which MERmaid can load. Does not explicitly load the DataFrame in MERmaid.

    Verifies that the save function throws an error when target assignments are not present, which
    are required by MERmaid.
    """
    r, c, z, y, x = 1, 5, 2, 2, 5
    data = np.zeros(100, dtype=np.float32).reshape(r, c, z, y, x)
    image_stack = ImageStack.from_numpy(data)
    intensities = IntensityTable.from_image_stack(image_stack)

    # without a target assignment, should raise RuntimeError.
    with pytest.raises(AttributeError):
        with TemporaryDirectory() as dir_:
            intensities.to_mermaid(os.path.join(dir_, 'test.csv.gz'))

    # assign targets
    intensities = factories.assign_synthetic_targets(intensities)
    with TemporaryDirectory() as dir_:
        intensities.to_mermaid(os.path.join(dir_, 'test.csv.gz'))
Esempio n. 15
0
def test_binarize(threshold: Number,
                  num_rounds=1,
                  num_chs=1,
                  num_zplanes=4,
                  ysize=5,
                  xsize=6):
    data = np.linspace(0,
                       1,
                       num_rounds * num_chs * num_zplanes * ysize * xsize,
                       dtype=np.float32)
    data = data.reshape((num_rounds, num_chs, num_zplanes, ysize, xsize))

    imagestack = ImageStack.from_numpy(data)
    binarizer = ThresholdBinarize(threshold)
    binary_mask_collection = binarizer.run(imagestack)

    assert len(binary_mask_collection) == 1
    mask = binary_mask_collection.uncropped_mask(0)

    expected_value = data[0, 0] >= threshold

    assert np.array_equal(mask, expected_value)
Esempio n. 16
0
def stack_from_tif(file_name: string) -> ImageStack:
    """
    Returns a starfish ImageStack object from a tif file
    Parameters
    ----------
    file_name: string
        Absolute or relative directory location of a tif file

    Returns
    -------
    ImageStack
    """
    image = sk.io.imread(file_name)
    image = sk.img_as_float(image)
    img_num = np.array(image)
    img_dim = len(np.shape(img_num))
    [img_ch, img_y, img_x] = [1, 1, 1]

    # Treat stacks of tiff's as multiple channels
    if img_dim == 3:
        [img_ch, img_y, img_x] = np.shape(img_num)

    if img_dim == 2:
        [img_y, img_x] = np.shape(img_num)
        img_ch = 1

    if not ((len(np.shape(img_num)) == 2) or (len(np.shape(img_num)) == 3)):
        raise Exception('Dimensionality error: images must be 2D or 2D stacks')

    stack = np.empty([1, img_ch, 1, img_y, img_x])

    if img_dim == 2:
        stack[0, 0, 0, :, :] = img_num[:, :]

    if img_dim == 3:
        stack[0, :, 0, :, :] = img_num[:, :, :]

    image_stack = ImageStack.from_numpy(stack)
    return image_stack
Esempio n. 17
0
def test_blob_doh_error_handling():
    """
    Test that BlobDetector throws a Value error if a user tries to use blob_doh on 3d data.
    `skimage.blob_doh` only supports 2d data.
    """
    stack = ImageStack.from_numpy(np.zeros((4, 2, 10, 100, 100), dtype=np.float32))

    blob_doh = BlobDetector(
        min_sigma=1,
        max_sigma=4,
        num_sigma=5,
        threshold=0,
        detector_method='blob_doh',
        measurement_type='max',
        is_volume=True)

    # Check that Value error gets raised when blob_doh and is_volume=True provided
    with pytest.raises(ValueError):
        blob_doh.run(stack)
    ref_image = stack.reduce({Axes.ROUND, Axes.CH}, func='max')
    # Check that Value error gets raised when blob_doh and reference image is 3d
    with pytest.raises(ValueError):
        blob_doh.run(stack, reference_image=ref_image)
Esempio n. 18
0
def decoded_intensity_table_factory() -> Tuple[IntensityTable, np.ndarray]:
    """
    Create an IntensityTable that has gene labels, including null labels. The data doesn't matter,
    so will use np.zeros
    """
    data = np.zeros((1, 1, 2, 3, 3), dtype=np.float32)
    labels = np.array(
        [[[0, 1, 1], [0, 2, 2], [1, 1, 1]], [[0, 1, 1], [1, 1, 1], [0, 1, 2]]],
        dtype='<U3')
    labels_with_nan = labels.copy()
    labels_with_nan[labels == '0'] = 'nan'

    # create an intensity table and add the labels
    image_stack = ImageStack.from_numpy(data)
    intensities = IntensityTable.from_image_stack(image_stack)
    intensities[Features.TARGET] = (Features.AXIS, np.ravel(labels_with_nan))

    # label the third column of this data as failing filters
    passes_filters = np.ones(data.shape, dtype=bool)
    passes_filters[:, :, :, :, -1] = 0
    intensities[Features.PASSES_THRESHOLDS] = (Features.AXIS,
                                               np.ravel(passes_filters))

    return intensities, labels_with_nan
Esempio n. 19
0
def test_intensity_table_can_be_constructed_from_an_imagestack():
    """
    ImageStack has enough information to create an IntensityTable without additional SpotAttributes.
    Each feature is a pixel, and therefore the SpotAttributes can be extracted from the relative
    locations.
    """
    r, c, z, y, x = 1, 5, 2, 2, 5
    data = np.zeros(100, dtype=np.float32).reshape(r, c, z, y, x)
    image_stack = ImageStack.from_numpy(data)
    intensities = IntensityTable.from_image_stack(image_stack)

    # there should be 100 features
    assert np.product(intensities.shape) == 100

    # the max features should be equal to the array extent (2, 2, 5) minus one, since indices
    # are being compared and python is zero based
    # import pdb; pdb.set_trace()
    assert np.max(intensities[Axes.ZPLANE.value].values) == z - 1
    assert np.max(intensities[Axes.Y.value].values) == y - 1
    assert np.max(intensities[Axes.X.value].values) == x - 1

    # the number of channels and rounds should match the ImageStack
    assert intensities.sizes[Axes.CH.value] == c
    assert intensities.sizes[Axes.ROUND.value] == r
Esempio n. 20
0
 def run(self, stack: ImageStack, *args) -> ImageStack:
     numpy_array = stack.xarray
     numpy_array = numpy_array * self.multiplicand
     return ImageStack.from_numpy(numpy_array)
Esempio n. 21
0
    def synthetic_spots(
        cls,
        intensities: IntensityTable,
        num_z: int,
        height: int,
        width: int,
        n_photons_background=1000,
        point_spread_function=(4, 2, 2),
        camera_detection_efficiency=0.25,
        background_electrons=1,
        graylevel: float = 37000.0 / 2**16,
        ad_conversion_bits=16,
    ) -> ImageStack:
        """Generate a synthetic ImageStack from a set of Features stored in an IntensityTable

        Parameters
        ----------
        intensities : IntensityTable
            IntensityTable containing coordinates of fluorophores. Used to position and generate
            spots in the output ImageStack
        num_z : int
            Number of z-planes in the ImageStack
        height : int
            Height in pixels of the ImageStack
        width : int
            Width in pixels of the ImageStack
        n_photons_background : int
            Poisson rate for the number of background photons to add to each pixel of the image.
            Set this parameter to 0 to eliminate background.
            (default 1000)
        point_spread_function : Tuple[int]
            The width of the gaussian density wherein photons spread around their light source.
            Set to zero to eliminate this (default (4, 2, 2))
        camera_detection_efficiency : float
            The efficiency of the camera to detect light. Set to 1 to remove this filter (default
            0.25)
        background_electrons : int
            Poisson rate for the number of spurious electrons detected per pixel during image
            capture by the camera (default 1)
        graylevel : float
            The number of shades of gray displayable by the synthetic camera. Larger numbers will
            produce higher resolution images (default 37000 / 2 ** 16)
        ad_conversion_bits : int
            The number of bits used during analog to visual conversion (default 16)

        Returns
        -------
        ImageStack :
            synthetic spots

        """
        # check some params
        if not 0 < camera_detection_efficiency <= 1:
            raise ValueError(
                f'invalid camera_detection_efficiency value: {camera_detection_efficiency}. '
                f'Must be in the interval (0, 1].')

        def select_uint_dtype(array):
            """choose appropriate dtype based on values of an array"""
            max_val = np.max(array)
            for dtype in (np.uint8, np.uint16, np.uint32):
                if max_val <= np.iinfo(dtype).max:
                    return array.astype(dtype)
            raise ValueError(
                'value exceeds dynamic range of largest skimage-supported type'
            )

        # make sure requested dimensions are large enough to support intensity values
        axis_to_size = zip((Axes.ZPLANE.value, Axes.Y.value, Axes.X.value),
                           (num_z, height, width))
        for axis, requested_size in axis_to_size:
            required_size = intensities.coords[axis].values.max() + 1
            if required_size > requested_size:
                raise ValueError(
                    f'locations of intensities contained in table exceed the size of requested '
                    f'axis {axis}. Required size {required_size} > {requested_size}.'
                )

        # create an empty array of the correct size
        image = np.zeros(
            (intensities.sizes[Axes.ROUND.value],
             intensities.sizes[Axes.CH.value], num_z, height, width),
            dtype=np.uint32)

        # starfish uses float images, but the logic here requires uint. We cast, and will cast back
        # at the end of the function
        intensities.values = img_as_uint(intensities)

        for ch, round_ in product(*(range(s) for s in intensities.shape[1:])):
            spots = intensities[:, ch, round_]

            # numpy deprecated casting a specific way of casting floats that is triggered in xarray
            with warnings.catch_warnings():
                warnings.simplefilter('ignore', FutureWarning)
                values = spots.where(spots, drop=True)

            image[round_, ch, values.z, values.y, values.x] = values

        intensities.values = img_as_float32(intensities)

        # add imaging noise
        image += np.random.poisson(n_photons_background,
                                   size=image.shape).astype(np.uint32)

        # blur image over coordinates, but not over round_/channels (dim 0, 1)
        sigma = (0, 0) + point_spread_function
        image = gaussian_filter(image, sigma=sigma, mode='nearest')

        image = image * camera_detection_efficiency

        image += np.random.normal(scale=background_electrons, size=image.shape)

        # mimic analog to digital conversion
        image = (image / graylevel).astype(int).clip(0, 2**ad_conversion_bits)

        # clip in case we've picked up some negative values
        image = np.clip(image, 0, a_max=None)

        # set the smallest int datatype that supports the data's intensity range
        image = select_uint_dtype(image)

        # convert to float for ImageStack
        with warnings.catch_warnings():
            # possible precision loss when casting from uint to float is acceptable
            warnings.simplefilter('ignore', UserWarning)
            image = img_as_float32(image)

        return ImageStack.from_numpy(image)
Esempio n. 22
0
from starfish.core.spots.FindSpots import FindSpotsAlgorithm
from starfish.core.test.factories import (
    two_spot_informative_blank_coded_data_factory,
    two_spot_one_hot_coded_data_factory,
    two_spot_sparse_coded_data_factory,
)
from starfish.types import Axes, Features, FunctionSource


# verify all spot finders handle different coding types
_, ONE_HOT_IMAGESTACK, ONE_HOT_MAX_INTENSITY = two_spot_one_hot_coded_data_factory()
_, SPARSE_IMAGESTACK, SPARSE_MAX_INTENSITY = two_spot_sparse_coded_data_factory()
_, BLANK_IMAGESTACK, BLANK_MAX_INTENSITY = two_spot_informative_blank_coded_data_factory()

# make sure that all spot finders handle empty arrays
EMPTY_IMAGESTACK = ImageStack.from_numpy(np.zeros((4, 2, 10, 100, 100), dtype=np.float32))


def simple_gaussian_spot_detector() -> BlobDetector:
    """create a basic gaussian spot detector"""
    return BlobDetector(
        min_sigma=1,
        max_sigma=4,
        num_sigma=5,
        threshold=0,
        measurement_type='max')


# initialize spot detectors
gaussian_spot_detector = simple_gaussian_spot_detector()
Esempio n. 23
0
 def run(self, stack: ImageStack, *args) -> ImageStack:
     numpy_array = stack.xarray
     numpy_array = numpy_array + stack.xarray
     return ImageStack.from_numpy(numpy_array)
Esempio n. 24
0
def generate_default_data():
    data = np.random.rand(2, 2, 2, 40, 50).astype(np.float32)
    return ImageStack.from_numpy(data)