diff --git a/README.md b/README.md
index 851ce88..dd63456 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# ![tiler_logo](https://user-images.githubusercontent.com/1889128/148645934-2b1545bc-e7ea-4f02-88fb-10100b6aa9be.png) tiler
+# ![tiler_baby_logo](misc/baby_logo.png) tiler
![Tiler teaser image](misc/teaser/tiler_teaser.png)
@@ -136,7 +136,8 @@ This section is a work in progress.
**How do I create tiles with less dimensions than the data array?**
-Tiler expects `tile_shape` to have the same length as `data_shape`.
-However you can specify the unwanted dimension as just 1.
-For example, if you want to get 2d tiles out from 3d array you can specify depth dimension of 1:
+Tiler expects `tile_shape` to have less than or the same number of elements as `data_shape`.
+If `tile_shape` has less elements than `data_shape`, `tile_shape` will be prepended with
+ones to match the size of `data_shape`.
+For example, if you want to get 2d tiles out from 3d array you can initialize Tiler like this: `Tiler(data_shape=(128,128,128), tile_shape=(128, 128))` and it will be equivalent to
`Tiler(data_shape=(128,128,128), tile_shape=(1, 128, 128))`.
diff --git a/docs/index.html b/docs/index.html
index 6867bad..5f7bf29 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -135,6 +135,9 @@
such as semantic segmentation in deep learning, especially in domains where images do not fit into GPU memory
(e.g., hyperspectral satellite images, whole slide images, videos, tomography data).
+
Please see Quick start section.
+If you want to use tiler interactively, I highly recommend napari and napari-tiler plugin.
+
Features
@@ -149,8 +152,7 @@ Features
Quick start
-This is an example of basic functionality.
-You can find more examples in examples.
+
You can find more examples in examples.
For more Tiler and Merger functionality, please check documentation.
import numpy as np
@@ -263,9 +265,10 @@ Frequently asked questions
How do I create tiles with less dimensions than the data array?
-Tiler expects tile_shape
to have the same length as data_shape
.
-However you can specify the unwanted dimension as just 1.
-For example, if you want to get 2d tiles out from 3d array you can specify depth dimension of 1:
+
Tiler expects tile_shape
to have less than or the same number of elements as data_shape
.
+If tile_shape
has less elements than data_shape
, tile_shape
will be prepended with
+ones to match the size of data_shape
.
+For example, if you want to get 2d tiles out from 3d array you can initialize Tiler like this: Tiler(data_shape=(128,128,128), tile_shape=(128, 128))
and it will be equivalent to
Tiler(data_shape=(128,128,128), tile_shape=(1, 128, 128))
.
@@ -298,10 +301,13 @@ Frequently asked questions
if "pdoc" in sys.modules: # pragma: no cover
with open("README.md", "r") as f:
_readme = f.read()
- _readme = _readme.split("# tiler", 1)[1] # remove header
- _readme = _readme.replace(
- "misc/teaser/tiler_teaser.png", "tiler_teaser.png"
- ) # replace image path
+
+ # remove baby logo and header
+ _readme = _readme.split("\n", 2)[2]
+
+ # replace teaser image path
+ _readme = _readme.replace("misc/teaser/tiler_teaser.png", "tiler_teaser.png")
+ _readme = _readme.replace("misc/baby_logo.png", "baby_logo.png")
__doc__ = _readme
@@ -360,7 +366,8 @@ Frequently asked questions
If there is a channel dimension, it should be included in the shape.
tile_shape (tuple, list or np.ndarray): Shape of a tile, e.g. (256, 256, 3), [64, 64, 64] or np.ndarray([3, 128, 128]).
- Tile must have the same number of dimensions as data.
+ Tile must have the same number of dimensions as data or less.
+ If less, the shape will be automatically prepended with ones to match data_shape size.
overlap (int, float, tuple, list or np.ndarray): Specifies overlap between tiles.
If integer, the same overlap of overlap pixels applied in each dimension, except channel_dimension.
@@ -406,19 +413,29 @@ Frequently asked questions
# Data and tile shapes
if data_shape is not None:
- self.data_shape = np.asarray(data_shape).astype(int)
+ self.data_shape = np.asarray(data_shape, dtype=np.int64)
if tile_shape is not None:
- self.tile_shape = np.asarray(tile_shape).astype(int)
+ self.tile_shape = np.atleast_1d(np.asarray(tile_shape, dtype=np.int64))
+
+ # Append ones to match data_shape size
+ if self.tile_shape.size <= self.data_shape.size:
+ size_difference = self.data_shape.size - self.tile_shape.size
+ self.tile_shape = np.insert(
+ arr=self.tile_shape, obj=0, values=np.ones(size_difference), axis=0
+ )
+ warnings.warn(
+ f"Tiler automatically adjusted tile_shape from {tuple(tile_shape)} to {tuple(self.tile_shape)}."
+ )
self._n_dim: int = len(self.data_shape)
if (self.tile_shape <= 0).any() or (self.data_shape <= 0).any():
raise ValueError(
- "Tile and data shapes must be tuple or lists of positive numbers."
+ "Tile and data shapes must be tuple, list or ndarray of positive integers."
)
if self.tile_shape.size != self.data_shape.size:
raise ValueError(
- "Tile and data shapes must have the same length. "
- "Hint: if you require tiles with less dimensions than data, put 1 in sliced dimensions, "
- "e.g. to get 1d 64px lines of 2d 64x64px image would mean tile_shape of (64, 1)."
+ "Tile shape must have less or equal number of elements compared to the data shape. "
+ "If less, your tile shape will be prepended with ones to match the data shape, "
+ "e.g. data_shape=(28, 28), tile_shape=(28) -> tile_shape=(1, 28)."
)
# Tiling mode
@@ -960,7 +977,8 @@ Frequently asked questions
If there is a channel dimension, it should be included in the shape.
tile_shape (tuple, list or np.ndarray): Shape of a tile, e.g. (256, 256, 3), [64, 64, 64] or np.ndarray([3, 128, 128]).
- Tile must have the same number of dimensions as data.
+ Tile must have the same number of dimensions as data or less.
+ If less, the shape will be automatically prepended with ones to match data_shape size.
overlap (int, float, tuple, list or np.ndarray): Specifies overlap between tiles.
If integer, the same overlap of overlap pixels applied in each dimension, except channel_dimension.
@@ -1002,7 +1020,8 @@ Args
- data_shape (tuple, list or np.ndarray): Input data shape, e.g. (1920, 1080, 3), [512, 512, 512] or np.ndarray([3, 1024, 768]).
If there is a channel dimension, it should be included in the shape.
- tile_shape (tuple, list or np.ndarray): Shape of a tile, e.g. (256, 256, 3), [64, 64, 64] or np.ndarray([3, 128, 128]).
-Tile must have the same number of dimensions as data.
+Tile must have the same number of dimensions as data or less.
+If less, the shape will be automatically prepended with ones to match data_shape size.
- overlap (int, float, tuple, list or np.ndarray): Specifies overlap between tiles.
If integer, the same overlap of overlap pixels applied in each dimension, except channel_dimension.
If float, percentage of a tile_shape to overlap (from 0.0 to 1.0), except channel_dimension.
@@ -1087,19 +1106,29 @@
Args
# Data and tile shapes
if data_shape is not None:
- self.data_shape = np.asarray(data_shape).astype(int)
+ self.data_shape = np.asarray(data_shape, dtype=np.int64)
if tile_shape is not None:
- self.tile_shape = np.asarray(tile_shape).astype(int)
+ self.tile_shape = np.atleast_1d(np.asarray(tile_shape, dtype=np.int64))
+
+ # Append ones to match data_shape size
+ if self.tile_shape.size <= self.data_shape.size:
+ size_difference = self.data_shape.size - self.tile_shape.size
+ self.tile_shape = np.insert(
+ arr=self.tile_shape, obj=0, values=np.ones(size_difference), axis=0
+ )
+ warnings.warn(
+ f"Tiler automatically adjusted tile_shape from {tuple(tile_shape)} to {tuple(self.tile_shape)}."
+ )
self._n_dim: int = len(self.data_shape)
if (self.tile_shape <= 0).any() or (self.data_shape <= 0).any():
raise ValueError(
- "Tile and data shapes must be tuple or lists of positive numbers."
+ "Tile and data shapes must be tuple, list or ndarray of positive integers."
)
if self.tile_shape.size != self.data_shape.size:
raise ValueError(
- "Tile and data shapes must have the same length. "
- "Hint: if you require tiles with less dimensions than data, put 1 in sliced dimensions, "
- "e.g. to get 1d 64px lines of 2d 64x64px image would mean tile_shape of (64, 1)."
+ "Tile shape must have less or equal number of elements compared to the data shape. "
+ "If less, your tile shape will be prepended with ones to match the data shape, "
+ "e.g. data_shape=(28, 28), tile_shape=(28) -> tile_shape=(1, 28)."
)
# Tiling mode
diff --git a/misc/baby_logo.png b/misc/baby_logo.png
new file mode 100644
index 0000000..bee964a
Binary files /dev/null and b/misc/baby_logo.png differ
diff --git a/misc/docs.sh b/misc/docs.sh
index 3b4e6f7..e6df956 100755
--- a/misc/docs.sh
+++ b/misc/docs.sh
@@ -1,4 +1,4 @@
-cd $(dirname "$file_name")/..
+cd "$(dirname "$file_name")"/.. || exit
# build docs
pdoc -o docs -d google tiler
diff --git a/tests/test_tiler.py b/tests/test_tiler.py
index d9b34f3..dfa54ea 100644
--- a/tests/test_tiler.py
+++ b/tests/test_tiler.py
@@ -35,6 +35,10 @@ def test_init(self):
overlap="unsupported_overlap",
)
+ # test tile shape broadcasting
+ tiler = Tiler(data_shape=(300, 300), tile_shape=(10,))
+ assert np.allclose(tiler.tile_shape, (1, 10))
+
def test_repr(self):
# gotta get that coverage
tiler = Tiler(
diff --git a/tiler/__init__.py b/tiler/__init__.py
index a719054..51bcf9e 100644
--- a/tiler/__init__.py
+++ b/tiler/__init__.py
@@ -25,8 +25,11 @@
if "pdoc" in sys.modules: # pragma: no cover
with open("README.md", "r") as f:
_readme = f.read()
- _readme = _readme.split("# tiler", 1)[1] # remove header
- _readme = _readme.replace(
- "misc/teaser/tiler_teaser.png", "tiler_teaser.png"
- ) # replace image path
+
+ # remove baby logo and header
+ _readme = _readme.split("\n", 2)[2]
+
+ # replace teaser image path
+ _readme = _readme.replace("misc/teaser/tiler_teaser.png", "tiler_teaser.png")
+ _readme = _readme.replace("misc/baby_logo.png", "baby_logo.png")
__doc__ = _readme
diff --git a/tiler/tiler.py b/tiler/tiler.py
index 3b1b55a..f51cbbe 100644
--- a/tiler/tiler.py
+++ b/tiler/tiler.py
@@ -47,7 +47,8 @@ def __init__(
If there is a channel dimension, it should be included in the shape.
tile_shape (tuple, list or np.ndarray): Shape of a tile, e.g. (256, 256, 3), [64, 64, 64] or np.ndarray([3, 128, 128]).
- Tile must have the same number of dimensions as data.
+ Tile must have the same number of dimensions as data or less.
+ If less, the shape will be automatically prepended with ones to match data_shape size.
overlap (int, float, tuple, list or np.ndarray): Specifies overlap between tiles.
If integer, the same overlap of overlap pixels applied in each dimension, except channel_dimension.
@@ -93,19 +94,29 @@ def recalculate(
# Data and tile shapes
if data_shape is not None:
- self.data_shape = np.asarray(data_shape).astype(int)
+ self.data_shape = np.asarray(data_shape, dtype=np.int64)
if tile_shape is not None:
- self.tile_shape = np.asarray(tile_shape).astype(int)
+ self.tile_shape = np.atleast_1d(np.asarray(tile_shape, dtype=np.int64))
+
+ # Append ones to match data_shape size
+ if self.tile_shape.size <= self.data_shape.size:
+ size_difference = self.data_shape.size - self.tile_shape.size
+ self.tile_shape = np.insert(
+ arr=self.tile_shape, obj=0, values=np.ones(size_difference), axis=0
+ )
+ warnings.warn(
+ f"Tiler automatically adjusted tile_shape from {tuple(tile_shape)} to {tuple(self.tile_shape)}."
+ )
self._n_dim: int = len(self.data_shape)
if (self.tile_shape <= 0).any() or (self.data_shape <= 0).any():
raise ValueError(
- "Tile and data shapes must be tuple or lists of positive numbers."
+ "Tile and data shapes must be tuple, list or ndarray of positive integers."
)
if self.tile_shape.size != self.data_shape.size:
raise ValueError(
- "Tile and data shapes must have the same length. "
- "Hint: if you require tiles with less dimensions than data, put 1 in sliced dimensions, "
- "e.g. to get 1d 64px lines of 2d 64x64px image would mean tile_shape of (64, 1)."
+ "Tile shape must have less or equal number of elements compared to the data shape. "
+ "If less, your tile shape will be prepended with ones to match the data shape, "
+ "e.g. data_shape=(28, 28), tile_shape=(28) -> tile_shape=(1, 28)."
)
# Tiling mode