def test_multiple_tiles_of_different_kind():
    with pytest.raises(TypeError):
        ImageStack.synthetic_stack(
            NUM_ROUND, NUM_CH, NUM_Z,
            HEIGHT, WIDTH,
            tile_fetcher=CornerDifferentDtype(np.uint32, np.float32),
        )
Beispiel #2
0
def test_fov_order():
    data = SyntheticData()
    codebook = data.codebook()
    stack1 = ImageStack.synthetic_stack()
    stack2 = ImageStack.synthetic_stack()
    fovs = [
        FieldOfView("stack2", {"primary": stack2}),
        FieldOfView("stack1", {"primary": stack1})
    ]
    extras = {"synthetic": True}
    experiment = Experiment(fovs, codebook, extras)
    assert "stack1" == experiment.fov().name
    assert ["stack1", "stack2"] == [x.name for x in experiment.fovs()]
def test_coordinates():
    """Set up an ImageStack with tiles that are offset based on round.  Verify that the coordinates
    retrieved match.
    """
    stack = ImageStack.synthetic_stack(NUM_ROUND,
                                       NUM_CH,
                                       NUM_Z,
                                       HEIGHT,
                                       WIDTH,
                                       tile_fetcher=tile_fetcher_factory(
                                           OffsettedTiles,
                                           True,
                                       ))

    for _round in range(NUM_ROUND):
        for ch in range(NUM_CH):
            for z in range(NUM_Z):
                indices = {Indices.ROUND: _round, Indices.CH: ch, Indices.Z: z}

                xmin, xmax = stack.tile_coordinates(indices, Coordinates.X)
                ymin, ymax = stack.tile_coordinates(indices, Coordinates.Y)
                zmin, zmax = stack.tile_coordinates(indices, Coordinates.Z)

                expected_xmin, expected_xmax = round_to_x(_round)
                expected_ymin, expected_ymax = round_to_y(_round)
                expected_zmin, expected_zmax = round_to_z(_round)

                assert np.isclose(xmin, expected_xmin)
                assert np.isclose(xmax, expected_xmax)
                assert np.isclose(ymin, expected_ymin)
                assert np.isclose(ymax, expected_ymax)
                assert np.isclose(zmin, expected_zmin)
                assert np.isclose(zmax, expected_zmax)
Beispiel #4
0
def test_scalar_coordinates():
    """Set up an ImageStack where only a single scalar physical coordinate is provided per axis.
    Internally, this should be converted to a range where the two endpoints are identical to the
    physical coordinate provided.
    """
    stack = ImageStack.synthetic_stack(NUM_ROUND,
                                       NUM_CH,
                                       NUM_Z,
                                       HEIGHT,
                                       WIDTH,
                                       tile_fetcher=tile_fetcher_factory(
                                           OffsettedScalarTiles,
                                           True,
                                       ))

    assert stack.tiles_aligned is False

    for selectors in stack._iter_axes({Axes.ROUND, Axes.CH, Axes.ZPLANE}):
        expected_x = round_to_x(selectors[Axes.ROUND])[0]
        expected_y = round_to_y(selectors[Axes.ROUND])[0]
        expected_z = round_to_z(selectors[Axes.ROUND])[0]

        verify_physical_coordinates(
            stack,
            selectors,
            (expected_x, expected_x),
            (expected_y, expected_y),
            (expected_z, expected_z),
        )
Beispiel #5
0
def test_missing_extras():
    """
    If the extras are not present on some of the tiles, it should still work.
    """
    class OnesTilesWithExtrasMostly(OnesTile):
        def __init__(self, fov, r, ch, z, extras: dict) -> None:
            super().__init__((10, 10))
            self.fov = fov
            self._extras = extras

        @property
        def extras(self):
            if self.fov == 0:
                return None
            return self._extras

    tile_fetcher = tile_fetcher_factory(OnesTilesWithExtrasMostly, True,
                                        {'random_key': {
                                            'hello': "world",
                                        }})

    stack = ImageStack.synthetic_stack(
        num_round=NUM_ROUND,
        num_ch=NUM_CH,
        num_z=NUM_Z,
        tile_fetcher=tile_fetcher,
    )
    table = stack.tile_metadata
    assert len(table) == NUM_ROUND * NUM_CH * NUM_Z
Beispiel #6
0
def test_apply_3d():
    """test that apply correctly applies a simple function across 3d volumes of a Stack"""
    stack = ImageStack.synthetic_stack()
    assert np.all(stack.xarray == 1)
    stack.apply(divide, in_place=True, value=4,
                group_by={Axes.ROUND, Axes.CH})
    assert (stack.xarray == 0.25).all()
Beispiel #7
0
def test_unaligned_tiles():
    """Test that imagestack error is thrown when constructed with unaligned tiles"""

    try:
        ImageStack.synthetic_stack(NUM_ROUND,
                                   NUM_CH,
                                   NUM_Z,
                                   HEIGHT,
                                   WIDTH,
                                   tile_fetcher=tile_fetcher_factory(
                                       OffsettedTiles,
                                       True,
                                   ))
    except ValueError as e:
        # Assert value error is thrown with right message
        assert e.args[0] == "Tiles must be aligned"
def test_scalar_coordinates():
    """Set up an ImageStack where only a single scalar physical coordinate is provided per axis.
    Internally, this should be converted to a range where the two endpoints are identical to the
    physical coordinate provided.
    """
    stack = ImageStack.synthetic_stack(NUM_ROUND,
                                       NUM_CH,
                                       NUM_Z,
                                       HEIGHT,
                                       WIDTH,
                                       tile_fetcher=tile_fetcher_factory(
                                           OffsettedScalarTiles,
                                           True,
                                       ))

    for _round in range(NUM_ROUND):
        for ch in range(NUM_CH):
            for z in range(NUM_Z):
                indices = {Indices.ROUND: _round, Indices.CH: ch, Indices.Z: z}

                xmin, xmax = stack.tile_coordinates(indices, Coordinates.X)
                ymin, ymax = stack.tile_coordinates(indices, Coordinates.Y)
                zmin, zmax = stack.tile_coordinates(indices, Coordinates.Z)

                expected_x = round_to_x(_round)[0]
                expected_y = round_to_y(_round)[0]
                expected_z = round_to_z(_round)[0]

                assert np.isclose(xmin, expected_x)
                assert np.isclose(xmax, expected_x)
                assert np.isclose(ymin, expected_y)
                assert np.isclose(ymax, expected_y)
                assert np.isclose(zmin, expected_z)
                assert np.isclose(zmax, expected_z)
Beispiel #9
0
def test_imagestack_export(tmpdir, format, count, recwarn):
    """
    Save a synthetic stack to files and check the results
    """
    stack = ImageStack.synthetic_stack()
    stack_json = tmpdir / "output.json"
    stack.export(str(stack_json), tile_format=format)
    files = list([x for x in tmpdir.listdir() if str(x).endswith(format.file_ext)])
    assert ImageStack.from_path_or_url(str(stack_json))
    assert count == len(files)
    with open(files[0], "rb") as fh:
        format.reader_func(fh)
def test_multiple_tiles_of_same_dtype():
    stack = ImageStack.synthetic_stack(
        NUM_ROUND,
        NUM_CH,
        NUM_Z,
        HEIGHT,
        WIDTH,
        tile_fetcher=CornerDifferentDtype(np.uint32, np.uint32),
    )
    expected = np.ones((NUM_ROUND, NUM_CH, NUM_Z, HEIGHT, WIDTH),
                       dtype=np.uint32)
    assert np.array_equal(stack.xarray, img_as_float32(expected))
Beispiel #11
0
def test_aligned_coordinates():
    """Set up an ImageStack where all the tiles are aligned (have the same physical coordinate values).
    Assert that the resulting Imagestack's tiles_aligned attribute is True
    """
    stack = ImageStack.synthetic_stack(NUM_ROUND,
                                       NUM_CH,
                                       NUM_Z,
                                       HEIGHT,
                                       WIDTH,
                                       tile_fetcher=tile_fetcher_factory(
                                           AlignedTiles,
                                           True,
                                       ))
    assert stack.tiles_aligned is True
def test_float_type_demotion():
    with warnings.catch_warnings(record=True) as warnings_:
        stack = ImageStack.synthetic_stack(
            NUM_ROUND,
            NUM_CH,
            NUM_Z,
            HEIGHT,
            WIDTH,
            tile_fetcher=CornerDifferentDtype(np.float64, np.float32),
        )
        assert len(warnings_) == 2
        assert issubclass(warnings_[0].category, DataFormatWarning)
        assert issubclass(warnings_[1].category, UserWarning)
    expected = np.ones((NUM_ROUND, NUM_CH, NUM_Z, HEIGHT, WIDTH),
                       dtype=np.float64)
    assert np.array_equal(stack.xarray, expected)
Beispiel #13
0
def test_set_slice_range():
    """
    Sets a slice across a range of one of the axes.
    """
    stack = ImageStack.synthetic_stack()
    zrange = slice(1, 3)
    y, x = stack.tile_shape

    expected = np.full((stack.shape[Axes.ROUND], stack.shape[Axes.CH],
                        zrange.stop - zrange.start + 1, y, x),
                       fill_value=0.5,
                       dtype=np.float32)
    index = {Axes.ZPLANE: zrange}

    stack.set_slice(index, expected, [Axes.ROUND, Axes.CH, Axes.ZPLANE])

    assert np.array_equal(stack.get_slice(index)[0], expected)
Beispiel #14
0
def test_conflict():
    """
    Tiles that have extras that conflict with indices should produce an error.
    """
    tile_fetcher = tile_fetcher_factory(OnesTilesWithExtras, False,
                                        {Indices.ROUND: {
                                            'hello': "world",
                                        }})

    stack = ImageStack.synthetic_stack(
        num_round=NUM_ROUND,
        num_ch=NUM_CH,
        num_z=NUM_Z,
        tile_fetcher=tile_fetcher,
    )
    with pytest.raises(ValueError):
        stack.tile_metadata
Beispiel #15
0
def test_set_slice_simple_index():
    """
    Sets a slice across one of the indices at the end.  For instance, if the dimensions are
    (P, Q0,..., Qn-1, R), sets a slice across either P or R.
    """
    stack = ImageStack.synthetic_stack()
    round_ = 1
    y, x = stack.tile_shape

    expected = np.full((stack.shape[Indices.CH], stack.shape[Indices.Z], y, x),
                       fill_value=0.5,
                       dtype=np.float32)
    index = {Indices.ROUND: round_}

    stack.set_slice(index, expected)

    assert np.array_equal(stack.get_slice(index)[0], expected)
Beispiel #16
0
def test_metadata():
    """
    Normal situation where all the tiles have uniform keys for both indices and extras.
    """
    tile_fetcher = tile_fetcher_factory(OnesTilesWithExtras, False,
                                        {'random_key': {
                                            'hello': "world",
                                        }})

    stack = ImageStack.synthetic_stack(
        num_round=NUM_ROUND,
        num_ch=NUM_CH,
        num_z=NUM_Z,
        tile_fetcher=tile_fetcher,
    )
    table = stack.tile_metadata
    assert len(table) == NUM_ROUND * NUM_CH * NUM_Z
Beispiel #17
0
def test_set_slice_middle_index():
    """
    Sets a slice across one of the indices in the middle.  For instance, if the dimensions are
    (P, Q0,..., Qn-1, R), slice across one of the Q axes.
    """
    stack = ImageStack.synthetic_stack()
    ch = 1
    y, x = stack.tile_shape

    expected = np.full(
        (stack.shape[Indices.ROUND], stack.shape[Indices.Z], y, x),
        fill_value=0.5,
        dtype=np.float32)
    index = {Indices.CH: ch}

    stack.set_slice(index, expected)

    assert np.array_equal(stack.get_slice(index)[0], expected)
Beispiel #18
0
def test_set_slice_simple_index():
    """
    Sets a slice across one of the axes at the end.  For instance, if the axes are
    (P, Q0,..., Qn-1, R), sets a slice across either P or R.  This test has expectations regarding
    the ordering of the axes in the ImageStack.
    """
    stack = ImageStack.synthetic_stack()
    round_ = 1
    y, x = stack.tile_shape

    expected = np.full((stack.shape[Axes.CH], stack.shape[Axes.ZPLANE], y, x),
                       fill_value=0.5,
                       dtype=np.float32)
    index = {Axes.ROUND: round_}

    stack.set_slice(index, expected, [Axes.CH, Axes.ZPLANE])

    assert np.array_equal(stack.get_slice(index)[0], expected)
Beispiel #19
0
def test_get_slice_range():
    """
    Retrieve a slice across a range of one of the dimensions.
    """
    stack = ImageStack.synthetic_stack()
    zrange = slice(1, 3)
    imageslice, axes = stack.get_slice({Axes.ZPLANE: zrange})
    y, x = stack.tile_shape
    assert axes == [Axes.ROUND, Axes.CH, Axes.ZPLANE]

    for round_ in range(stack.shape[Axes.ROUND]):
        for ch in range(stack.shape[Axes.CH]):
            for z in range(zrange.stop - zrange.start):
                data = np.empty((y, x))
                data.fill((round_ * stack.shape[Axes.CH] + ch) *
                          stack.shape[Axes.ZPLANE] + (z + zrange.start))

                assert data.all() == imageslice[round_, ch, z].all()
Beispiel #20
0
def test_coordinates():
    """Set up an ImageStack with tiles that are aligned.  Verify that the coordinates
    retrieved match.
    """
    stack = ImageStack.synthetic_stack(NUM_ROUND,
                                       NUM_CH,
                                       NUM_Z,
                                       HEIGHT,
                                       WIDTH,
                                       tile_fetcher=tile_fetcher_factory(
                                           AlignedTiles,
                                           True,
                                       ))
    for selectors in stack._iter_axes({Axes.ZPLANE}):
        verify_physical_coordinates(
            stack, X_COORDS, Y_COORDS,
            get_physical_coordinates_of_z_plane(
                zplane_to_z(selectors[Axes.ZPLANE])), selectors[Axes.ZPLANE])
def test_int_type_promotion():
    with warnings.catch_warnings(record=True) as warnings_:
        stack = ImageStack.synthetic_stack(
            NUM_ROUND,
            NUM_CH,
            NUM_Z,
            HEIGHT,
            WIDTH,
            tile_fetcher=CornerDifferentDtype(np.int32, np.int8),
        )
        assert len(warnings_) == 2
        assert issubclass(warnings_[0].category, DataFormatWarning)
        assert issubclass(warnings_[1].category, UserWarning)
    expected = img_as_float32(
        np.ones((NUM_ROUND, NUM_CH, NUM_Z, HEIGHT, WIDTH), dtype=np.int32))
    corner = img_as_float32(np.ones((HEIGHT, WIDTH), dtype=np.int8))
    expected[0, 0, 0] = corner
    assert np.array_equal(stack.xarray, img_as_float32(expected))
Beispiel #22
0
def test_get_slice_middle_index():
    """
    Retrieve a slice across one of the indices in the middle.  For instance, if the dimensions are
    (P, Q0,..., Qn-1, R), slice across one of the Q axes.
    """
    stack = ImageStack.synthetic_stack()
    ch = 1
    imageslice, axes = stack.get_slice({Indices.CH: ch})
    assert axes == [Indices.ROUND, Indices.Z]

    y, x = stack.tile_shape

    for round_ in range(stack.shape[Indices.ROUND]):
        for z in range(stack.shape[Indices.Z]):
            data = np.empty((y, x))
            data.fill((round_ * stack.shape[Indices.CH] + ch) *
                      stack.shape[Indices.Z] + z)

            assert data.all() == imageslice[round_, z].all()
Beispiel #23
0
def test_set_slice_reorder():
    """
    Sets a slice across one of the axes.  The source data is not in the same order as the axes in
    ImageStack, but set_slice should reorder the axes and write it correctly.
    """
    stack = ImageStack.synthetic_stack()
    round_ = 1
    y, x = stack.tile_shape
    index = {Axes.ROUND: round_}

    written = np.full((stack.shape[Axes.ZPLANE], stack.shape[Axes.CH], y, x),
                      fill_value=0.5,
                      dtype=np.float32)
    stack.set_slice(index, written, [Axes.ZPLANE, Axes.CH])

    expected = np.full((stack.shape[Axes.CH], stack.shape[Axes.ZPLANE], y, x),
                       fill_value=0.5,
                       dtype=np.float32)
    assert np.array_equal(stack.get_slice(index)[0], expected)
Beispiel #24
0
def test_get_slice_simple_index():
    """
    Retrieve a slice across one of the indices at the end.  For instance, if the dimensions are
    (P, Q0,..., Qn-1, R), slice across either P or R.
    """
    stack = ImageStack.synthetic_stack()
    round_ = 1
    imageslice, axes = stack.get_slice({Indices.ROUND: round_})
    assert axes == [Indices.CH, Indices.Z]

    y, x = stack.tile_shape

    for ch in range(stack.shape[Indices.CH]):
        for z in range(stack.shape[Indices.Z]):
            data = np.empty((y, x))
            data.fill((round_ * stack.shape[Indices.CH] + ch) *
                      stack.shape[Indices.Z] + z)

            assert data.all() == imageslice[ch, z].all()
Beispiel #25
0
def test_get_slice_middle_index():
    """
    Retrieve a slice across one of the axes in the middle.  For instance, if the axes are
    (P, Q0,..., Qn-1, R), slice across one of the Q axes.  This test has expectations regarding the
    ordering of the axes in the ImageStack.
    """
    stack = ImageStack.synthetic_stack()
    ch = 1
    imageslice, axes = stack.get_slice({Axes.CH: ch})
    assert axes == [Axes.ROUND, Axes.ZPLANE]

    y, x = stack.tile_shape

    for round_ in range(stack.shape[Axes.ROUND]):
        for z in range(stack.shape[Axes.ZPLANE]):
            data = np.empty((y, x))
            data.fill((round_ * stack.shape[Axes.CH] + ch) *
                      stack.shape[Axes.ZPLANE] + z)

            assert data.all() == imageslice[round_, z].all()
Beispiel #26
0
def test_coordinates():
    """Set up an ImageStack with tiles that are offset based on round.  Verify that the coordinates
    retrieved match.
    """
    stack = ImageStack.synthetic_stack(NUM_ROUND,
                                       NUM_CH,
                                       NUM_Z,
                                       HEIGHT,
                                       WIDTH,
                                       tile_fetcher=tile_fetcher_factory(
                                           OffsettedTiles,
                                           True,
                                       ))

    assert stack.tiles_aligned is False

    for selectors in stack._iter_axes({Axes.ROUND, Axes.CH, Axes.ZPLANE}):
        verify_physical_coordinates(
            stack,
            selectors,
            round_to_x(selectors[Axes.ROUND]),
            round_to_y(selectors[Axes.ROUND]),
            round_to_z(selectors[Axes.ROUND]),
        )
Beispiel #27
0
def test_scalar_coordinates():
    """Set up an ImageStack where only a single scalar physical coordinate is provided per axis.
    Internally, this should be converted to a range where the two endpoints are identical to the
    physical coordinate provided.
    """
    stack = ImageStack.synthetic_stack(NUM_ROUND,
                                       NUM_CH,
                                       NUM_Z,
                                       HEIGHT,
                                       WIDTH,
                                       tile_fetcher=tile_fetcher_factory(
                                           ScalarTiles,
                                           True,
                                       ))

    expected_x = X_COORDS[0]
    expected_y = Y_COORDS[0]

    for selectors in stack._iter_axes({Axes.ZPLANE}):
        expected_z = zplane_to_z(selectors[Axes.ZPLANE])[0]
        verify_physical_coordinates(
            stack, (expected_x, expected_x), (expected_y, expected_y),
            get_physical_coordinates_of_z_plane((expected_z, expected_z)),
            selectors[Axes.ZPLANE])
Beispiel #28
0
def test_imagestack_indexing():
    """Tests indexing on an Imagestack with a shape (5, 5, 15, 200, 200)
        steps:
        1.) stack.sel(indexers)
        2.) assert new shape of stack is what we expect

    """

    stack = ImageStack.synthetic_stack(num_round=5,
                                       num_ch=5,
                                       num_z=15,
                                       tile_height=200,
                                       tile_width=200)

    # index on range of rounds and single ch and Z
    indexed = stack.sel({
        Indices.ROUND: (1, None),
        Indices.CH: 0,
        Indices.Z: 0
    })
    expected_shape = OrderedDict([(Indices.ROUND, 4), (Indices.CH, 1),
                                  (Indices.Z, 1), (Indices.Y, 200),
                                  (Indices.X, 200)])
    assert indexed.shape == expected_shape

    # index on single round ch and z
    indexed = stack.sel({Indices.ROUND: 0, Indices.CH: 0, Indices.Z: 0})
    expected_shape = OrderedDict([(Indices.ROUND, 1), (Indices.CH, 1),
                                  (Indices.Z, 1), (Indices.Y, 200),
                                  (Indices.X, 200)])
    assert indexed.shape == expected_shape

    # index on single round and range of ch
    indexed = stack.sel({Indices.ROUND: 1, Indices.CH: (3, None)})
    expected_shape = OrderedDict([(Indices.ROUND, 1), (Indices.CH, 2),
                                  (Indices.Z, 15), (Indices.Y, 200),
                                  (Indices.X, 200)])
    assert indexed.shape == expected_shape

    # index on single round and range of ch and Z
    indexed = stack.sel({
        Indices.ROUND: 1,
        Indices.CH: (None, 3),
        Indices.Z: (7, None)
    })
    expected_shape = OrderedDict([(Indices.ROUND, 1), (Indices.CH, 3),
                                  (Indices.Z, 8), (Indices.Y, 200),
                                  (Indices.X, 200)])
    assert indexed.shape == expected_shape

    # index on first half of X and single value of Y
    indexed_stack = stack.sel({
        Indices.ROUND: 0,
        Indices.CH: 0,
        Indices.Z: 1,
        Indices.Y: 100,
        Indices.X: (None, 100)
    })
    expected_shape = OrderedDict([(Indices.ROUND, 1), (Indices.CH, 1),
                                  (Indices.Z, 1), (Indices.Y, 1),
                                  (Indices.X, 100)])
    assert indexed_stack.shape == expected_shape

    # index on first half of X and Y
    indexed_stack = stack.sel({Indices.Y: (None, 100), Indices.X: (None, 100)})

    expected_shape = OrderedDict([(Indices.ROUND, 5), (Indices.CH, 5),
                                  (Indices.Z, 15), (Indices.Y, 100),
                                  (Indices.X, 100)])
    assert indexed_stack.shape == expected_shape

    # index on single x and y
    indexed_stack = stack.sel({
        Indices.ROUND: 0,
        Indices.CH: 0,
        Indices.Z: 1,
        Indices.Y: 100,
        Indices.X: 150
    })
    expected_shape = OrderedDict([(Indices.ROUND, 1), (Indices.CH, 1),
                                  (Indices.Z, 1), (Indices.Y, 1),
                                  (Indices.X, 1)])
    assert indexed_stack.shape == expected_shape

    # Negative indexing
    indexed_stack = stack.sel({
        Indices.ROUND: 0,
        Indices.CH: 0,
        Indices.Z: 1,
        Indices.Y: (None, -10),
        Indices.X: (None, -10)
    })
    expected_shape = OrderedDict([(Indices.ROUND, 1), (Indices.CH, 1),
                                  (Indices.Z, 1), (Indices.Y, 190),
                                  (Indices.X, 190)])
    assert indexed_stack.shape == expected_shape
Beispiel #29
0
def test_apply_single_process():
    """test that apply correctly applies a simple function across 2d tiles of a Stack"""
    stack = ImageStack.synthetic_stack()
    assert (stack.xarray == 1).all()
    output = stack.apply(divide, value=2, n_processes=1)
    assert (output.xarray == 0.5).all()