Source code for tiling

from abc import ABCMeta, abstractmethod
import math

try:
    from collections.abc import Sequence
except ImportError:
    from collections import Sequence

from six import with_metaclass


__version__ = "0.3.0"


class BaseTiles(with_metaclass(ABCMeta, object)):
    """
    Base class to tile an image.
    See the implementations
        - ConstSizeTiles
        - ConstStrideTiles
    """

    def __init__(self, image_size, tile_size=(128, 128), scale=1.0):
        """Initialize tiles

        Args:
            image_size (list/tuple): input image size in pixels
            tile_size (int or list/tuple): output tile size in pixels
            scale (float): tile scaling factor
        """

        if not (isinstance(image_size, Sequence) and len(image_size) == 2):
            raise TypeError("Argument image_size should be (sx, sy)")
        for s in image_size:
            if s < 1:
                raise ValueError("Values of image_size should be positive")

        if not (isinstance(tile_size, int) or (isinstance(tile_size, Sequence) and len(tile_size) == 2)):
            raise TypeError("Argument tile_size should be either int or pair of integers (sx, sy)")
        if isinstance(tile_size, int):
            tile_size = (tile_size, tile_size)
        for s in tile_size:
            if s < 1:
                raise ValueError("Values of tile_size should be positive")

        if scale <= 0:
            raise ValueError("Argument scale should be positive")

        for tile_dim, img_dim in zip(tile_size, image_size):
            if int(tile_dim / scale) >= img_dim:
                raise ValueError(
                    "Scale {} and tile size {} should not be larger "
                    "than image size {}".format(scale, tile_dim, img_dim)
                )

        self.image_size = image_size
        self.tile_size = tile_size
        self.scale = float(scale)
        # Apply floor to tile extent (tile size / scale)
        # Output size is then ceil(extent * scale), extent is <= tile_extent
        # ceil(extent * scale) < ceil(tile_extent * scale) = ceil(floor(tile_extent / scale) * scale)<= tile_size
        self.tile_extent = [int(math.floor(d / self.scale)) for d in self.tile_size]
        self._index = 0
        self._max_index = 0

    @abstractmethod
    def __len__(self):
        """Method to get total number of tiles
        """

    @abstractmethod
    def __getitem__(self, idx):
        """Method to get the tile at index

        Args:
            idx: (int)
        """

    def next(self):
        """Method to get next tile

        Returns:
            tile data (ndarray), tile extent (list) in the original image, in pixels
        """
        if self._index < 0 or self._index >= self._max_index:
            raise StopIteration()

        res = self[self._index]
        # ++
        self._index += 1

        return res

    __next__ = next


def ceil_int(x):
    return int(math.ceil(x))


from tiling.const_stride import ConstStrideTiles
from tiling.const_size import ConstSizeTiles