InvokeAI/invokeai/backend/vto_workflow/seamless_mapping.py
2024-07-25 14:48:39 -04:00

32 lines
1.4 KiB
Python

import math
import numpy as np
from PIL import Image
def map_seamless_tiles(seamless_tile: Image.Image, target_hw: tuple[int, int], num_repeats_h: float) -> Image.Image:
"""Map seamless tiles to a target size with a given number of repeats along the height dimension."""
# TODO(ryand): Add option to flip odd rows and columns if the tile is not seamless.
# - May also want the option to decide on a per-axis basis.
target_h, target_w = target_hw
# Calculate the height of the tile that is necessary to achieve the desired number of repeats.
# Take the ceiling so that the last tile overflows the target height.
target_tile_h = math.ceil(target_h / num_repeats_h)
# Resize the tile to the target height.
# Determine the target_tile_w that preserves the original aspect ratio.
target_tile_w = int(target_tile_h / seamless_tile.height * seamless_tile.width)
resized_tile = seamless_tile.resize((target_tile_w, target_tile_h))
# Repeat the tile along the height and width dimensions.
num_repeats_h_int = math.ceil(num_repeats_h)
num_repeats_w_int = math.ceil(target_w / target_tile_w)
seamless_tiles_np = np.array(resized_tile)
repeated_tiles_np = np.tile(seamless_tiles_np, (num_repeats_h_int, num_repeats_w_int, 1))
# Crop the repeated tiles to the target size.
output_pattern = Image.fromarray(repeated_tiles_np[:target_h, :target_w])
return output_pattern