Source code for cv2ext.image._tiling

# Copyright (c) 2024 Justin Davis (davisjustin302@gmail.com)
#
# MIT License
from __future__ import annotations

from typing import TYPE_CHECKING

import numpy as np

if TYPE_CHECKING:
    from collections.abc import Generator


[docs] def create_tiled_image( tile: np.ndarray, base: np.ndarray | None = None, tile_shape: tuple[int, int] | None = None, image_shape: tuple[int, int] | None = None, ) -> np.ndarray: """ Tile an image across another image, or create a new image of the tile. Parameters ---------- tile : np.ndarray The image to tile across the base image. base : np.ndarray, optional The base image to tile the image across. If provided, the tiles will be placed across the image in a grid pattern. Only placing a tile where the entrie tile can fit (i.e. no partial tiles). Only one of base, tile_shape, or image_shape can be provided. tile_shape : tuple[int, int], optional The shape of the tiles to create. This should be in the form of (rows, cols). Where rows is the number of tiles in the y direction, and cols is the number of tiles in the x direction. Only one of base, tile_shape, or image_shape can be provided. image_shape : tuple[int, int], optional The shape of the image to create. This should be in the form of (height, width). This is used to create a new image based on the tiles. Only one of base, tile_shape, or image_shape can be provided. Returns ------- np.ndarray The tiled image. Raises ------ ValueError If no base, tile shape, or image shape is provided. ValueError If more than one of base, tile shape, or image shape is provided. """ overlay_height, overlay_width = tile.shape[:2] if base is None and tile_shape is None and image_shape is None: err_msg = "Either base, tile shape, or image shape must be provided." raise ValueError(err_msg) if base is not None and tile_shape is not None and image_shape is not None: err_msg = "Only one of base, tile shape, or image shape can be provided." raise ValueError(err_msg) # compute the shape of the base image and create if needed if base is not None: base_image = base base_height, base_width = base.shape[:2] elif tile_shape is not None: base_shape = tile_shape[0] * overlay_height, tile_shape[1] * overlay_width, 3 base_image = np.ones(base_shape, dtype=np.uint8) * 255 base_height, base_width = base_shape[:2] elif image_shape is not None: base_image = np.ones((image_shape[0], image_shape[1], 3), dtype=np.uint8) * 255 base_height, base_width = base_image.shape[:2] else: err_msg = "Either base, tile shape, or image shape must be provided." raise ValueError(err_msg) # current indices x = 0 y = 0 # make a copy of the base image canvas: np.ndarray = base_image.copy() while y < base_height and y + overlay_height <= base_height: while x < base_width and x + overlay_width <= base_width: canvas[y : y + overlay_height, x : x + overlay_width] = tile x += overlay_width x = 0 y += overlay_height return canvas
[docs] def image_tiler( base: np.ndarray, tile: np.ndarray, ) -> Generator[np.ndarray, None, None]: """ Tile an image across another image. This function yields images with the tile progressively tiling across the base image. Each tile is placed in a grid fashion in row then column order. All tiles stay on the image, such that the final image produced will be fully filed (without partial fills). The first image produced will be the base image. Parameters ---------- base : np.ndarray The base image to tile the image across. tile : np.ndarray The image to tile across the base image. Yields ------ np.ndarray The tiled image. """ overlay_height, overlay_width = tile.shape[:2] base_height, base_width = base.shape[:2] # current indices x = 0 y = 0 # make a copy of the base image canvas: np.ndarray = base.copy() yield canvas while y < base_height and y + overlay_height <= base_height: while x < base_width and x + overlay_width <= base_width: canvas[y : y + overlay_height, x : x + overlay_width] = tile yield canvas x += overlay_width x = 0 y += overlay_height yield canvas