mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
- Even_spilt overlap renamed to overlap_fraction
- min_overlap removed * restrictions and round_to_8 - min_overlap handles tile size > image size by clipping the num tiles to 1. - Updated assert test on min_overlap.
This commit is contained in:
parent
4c97b619fb
commit
fefb78795f
@ -88,7 +88,7 @@ class CalculateImageTilesEvenSplitInvocation(BaseInvocation):
|
|||||||
ge=1,
|
ge=1,
|
||||||
description="Number of tiles to divide image into on the y axis",
|
description="Number of tiles to divide image into on the y axis",
|
||||||
)
|
)
|
||||||
overlap: float = InputField(
|
overlap_fraction: float = InputField(
|
||||||
default=0.25,
|
default=0.25,
|
||||||
ge=0,
|
ge=0,
|
||||||
lt=1,
|
lt=1,
|
||||||
@ -101,7 +101,7 @@ class CalculateImageTilesEvenSplitInvocation(BaseInvocation):
|
|||||||
image_width=self.image_width,
|
image_width=self.image_width,
|
||||||
num_tiles_x=self.num_tiles_x,
|
num_tiles_x=self.num_tiles_x,
|
||||||
num_tiles_y=self.num_tiles_y,
|
num_tiles_y=self.num_tiles_y,
|
||||||
overlap=self.overlap,
|
overlap_fraction=self.overlap_fraction,
|
||||||
)
|
)
|
||||||
return CalculateImageTilesOutput(tiles=tiles)
|
return CalculateImageTilesOutput(tiles=tiles)
|
||||||
|
|
||||||
@ -120,18 +120,9 @@ class CalculateImageTilesMinimumOverlapInvocation(BaseInvocation):
|
|||||||
image_height: int = InputField(
|
image_height: int = InputField(
|
||||||
ge=1, default=1024, description="The image height, in pixels, to calculate tiles for."
|
ge=1, default=1024, description="The image height, in pixels, to calculate tiles for."
|
||||||
)
|
)
|
||||||
tile_width: int = InputField(ge=1, default=576, multiple_of=8, description="The tile width, in pixels.")
|
tile_width: int = InputField(ge=1, default=576, description="The tile width, in pixels.")
|
||||||
tile_height: int = InputField(ge=1, default=576, multiple_of=8, description="The tile height, in pixels.")
|
tile_height: int = InputField(ge=1, default=576, description="The tile height, in pixels.")
|
||||||
min_overlap: int = InputField(
|
min_overlap: int = InputField(default=128, ge=0, description="Minimum overlap between adjacent tiles, in pixels.")
|
||||||
default=128,
|
|
||||||
ge=0,
|
|
||||||
multiple_of=8,
|
|
||||||
description="Minimum overlap between adjacent tiles, in pixels(must be a multiple of 8).",
|
|
||||||
)
|
|
||||||
round_to_8: bool = InputField(
|
|
||||||
default=False,
|
|
||||||
description="Round outputs down to the nearest 8 (for pulling from a large noise field)",
|
|
||||||
)
|
|
||||||
|
|
||||||
def invoke(self, context: InvocationContext) -> CalculateImageTilesOutput:
|
def invoke(self, context: InvocationContext) -> CalculateImageTilesOutput:
|
||||||
tiles = calc_tiles_min_overlap(
|
tiles = calc_tiles_min_overlap(
|
||||||
@ -140,7 +131,6 @@ class CalculateImageTilesMinimumOverlapInvocation(BaseInvocation):
|
|||||||
tile_height=self.tile_height,
|
tile_height=self.tile_height,
|
||||||
tile_width=self.tile_width,
|
tile_width=self.tile_width,
|
||||||
min_overlap=self.min_overlap,
|
min_overlap=self.min_overlap,
|
||||||
round_to_8=self.round_to_8,
|
|
||||||
)
|
)
|
||||||
return CalculateImageTilesOutput(tiles=tiles)
|
return CalculateImageTilesOutput(tiles=tiles)
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ def calc_tiles_with_overlap(
|
|||||||
|
|
||||||
|
|
||||||
def calc_tiles_even_split(
|
def calc_tiles_even_split(
|
||||||
image_height: int, image_width: int, num_tiles_x: int, num_tiles_y: int, overlap: float = 0
|
image_height: int, image_width: int, num_tiles_x: int, num_tiles_y: int, overlap_fraction: float = 0
|
||||||
) -> list[Tile]:
|
) -> list[Tile]:
|
||||||
"""Calculate the tile coordinates for a given image shape with the number of tiles requested.
|
"""Calculate the tile coordinates for a given image shape with the number of tiles requested.
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ def calc_tiles_even_split(
|
|||||||
image_width (int): The image width in px.
|
image_width (int): The image width in px.
|
||||||
num_x_tiles (int): The number of tile to split the image into on the X-axis.
|
num_x_tiles (int): The number of tile to split the image into on the X-axis.
|
||||||
num_y_tiles (int): The number of tile to split the image into on the Y-axis.
|
num_y_tiles (int): The number of tile to split the image into on the Y-axis.
|
||||||
overlap (float, optional): The target overlap amount of the tiles size. Defaults to 0.
|
overlap_fraction (float, optional): The target overlap as fraction of the tiles size. Defaults to 0.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[Tile]: A list of tiles that cover the image shape. Ordered from left-to-right, top-to-bottom.
|
list[Tile]: A list of tiles that cover the image shape. Ordered from left-to-right, top-to-bottom.
|
||||||
@ -119,11 +119,15 @@ def calc_tiles_even_split(
|
|||||||
|
|
||||||
# Ensure tile size is divisible by 8
|
# Ensure tile size is divisible by 8
|
||||||
if image_width % LATENT_SCALE_FACTOR != 0 or image_height % LATENT_SCALE_FACTOR != 0:
|
if image_width % LATENT_SCALE_FACTOR != 0 or image_height % LATENT_SCALE_FACTOR != 0:
|
||||||
raise ValueError(f"image size (({image_width}, {image_height})) must be divisible by 8")
|
raise ValueError(f"image size (({image_width}, {image_height})) must be divisible by {LATENT_SCALE_FACTOR}")
|
||||||
|
|
||||||
# Calculate the overlap size based on the percentage and adjust it to be divisible by 8 (rounding up)
|
# Calculate the overlap size based on the percentage and adjust it to be divisible by 8 (rounding up)
|
||||||
overlap_x = LATENT_SCALE_FACTOR * math.ceil(int((image_width / num_tiles_x) * overlap) / LATENT_SCALE_FACTOR)
|
overlap_x = LATENT_SCALE_FACTOR * math.ceil(
|
||||||
overlap_y = LATENT_SCALE_FACTOR * math.ceil(int((image_height / num_tiles_y) * overlap) / LATENT_SCALE_FACTOR)
|
int((image_width / num_tiles_x) * overlap_fraction) / LATENT_SCALE_FACTOR
|
||||||
|
)
|
||||||
|
overlap_y = LATENT_SCALE_FACTOR * math.ceil(
|
||||||
|
int((image_height / num_tiles_y) * overlap_fraction) / LATENT_SCALE_FACTOR
|
||||||
|
)
|
||||||
|
|
||||||
# Calculate the tile size based on the number of tiles and overlap, and ensure it's divisible by 8 (rounding down)
|
# Calculate the tile size based on the number of tiles and overlap, and ensure it's divisible by 8 (rounding down)
|
||||||
tile_size_x = LATENT_SCALE_FACTOR * math.floor(
|
tile_size_x = LATENT_SCALE_FACTOR * math.floor(
|
||||||
@ -184,11 +188,11 @@ def calc_tiles_min_overlap(
|
|||||||
Returns:
|
Returns:
|
||||||
list[Tile]: A list of tiles that cover the image shape. Ordered from left-to-right, top-to-bottom.
|
list[Tile]: A list of tiles that cover the image shape. Ordered from left-to-right, top-to-bottom.
|
||||||
"""
|
"""
|
||||||
assert image_height >= tile_height
|
|
||||||
assert image_width >= tile_width
|
|
||||||
assert min_overlap < tile_height
|
assert min_overlap < tile_height
|
||||||
assert min_overlap < tile_width
|
assert min_overlap < tile_width
|
||||||
|
|
||||||
|
# The If Else catches the case when the tile size is larger than the images size and just clips the number of tiles to 1
|
||||||
num_tiles_x = math.ceil((image_width - min_overlap) / (tile_width - min_overlap)) if tile_width < image_width else 1
|
num_tiles_x = math.ceil((image_width - min_overlap) / (tile_width - min_overlap)) if tile_width < image_width else 1
|
||||||
num_tiles_y = (
|
num_tiles_y = (
|
||||||
math.ceil((image_height - min_overlap) / (tile_height - min_overlap)) if tile_height < image_height else 1
|
math.ceil((image_height - min_overlap) / (tile_height - min_overlap)) if tile_height < image_height else 1
|
||||||
@ -200,14 +204,10 @@ def calc_tiles_min_overlap(
|
|||||||
# Calculate tile coordinates. (Ignore overlap values for now.)
|
# Calculate tile coordinates. (Ignore overlap values for now.)
|
||||||
for tile_idx_y in range(num_tiles_y):
|
for tile_idx_y in range(num_tiles_y):
|
||||||
top = (tile_idx_y * (image_height - tile_height)) // (num_tiles_y - 1) if num_tiles_y > 1 else 0
|
top = (tile_idx_y * (image_height - tile_height)) // (num_tiles_y - 1) if num_tiles_y > 1 else 0
|
||||||
if round_to_8:
|
|
||||||
top = LATENT_SCALE_FACTOR * (top // LATENT_SCALE_FACTOR)
|
|
||||||
bottom = top + tile_height
|
bottom = top + tile_height
|
||||||
|
|
||||||
for tile_idx_x in range(num_tiles_x):
|
for tile_idx_x in range(num_tiles_x):
|
||||||
left = (tile_idx_x * (image_width - tile_width)) // (num_tiles_x - 1) if num_tiles_x > 1 else 0
|
left = (tile_idx_x * (image_width - tile_width)) // (num_tiles_x - 1) if num_tiles_x > 1 else 0
|
||||||
if round_to_8:
|
|
||||||
left = LATENT_SCALE_FACTOR * (left // LATENT_SCALE_FACTOR)
|
|
||||||
right = left + tile_width
|
right = left + tile_width
|
||||||
|
|
||||||
tile = Tile(
|
tile = Tile(
|
||||||
|
@ -74,6 +74,9 @@ def seam_blend(ia1: np.ndarray, ia2: np.ndarray, blend_amount: int, x_seam: bool
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
# Assume RGB and convert to grey
|
# Assume RGB and convert to grey
|
||||||
|
# Could offer other options for the luminance conversion
|
||||||
|
# BT.709 [0.2126, 0.7152, 0.0722], BT.2020 [0.2627, 0.6780, 0.0593])
|
||||||
|
# it might not have a huge impact due to the blur that is applied over the seam
|
||||||
iag1 = np.dot(ia1, [0.2989, 0.5870, 0.1140]) # BT.601 perceived brightness
|
iag1 = np.dot(ia1, [0.2989, 0.5870, 0.1140]) # BT.601 perceived brightness
|
||||||
iag2 = np.dot(ia2, [0.2989, 0.5870, 0.1140])
|
iag2 = np.dot(ia2, [0.2989, 0.5870, 0.1140])
|
||||||
|
|
||||||
@ -92,6 +95,7 @@ def seam_blend(ia1: np.ndarray, ia2: np.ndarray, blend_amount: int, x_seam: bool
|
|||||||
min_x = gutter
|
min_x = gutter
|
||||||
|
|
||||||
# Calc the energy in the difference
|
# Calc the energy in the difference
|
||||||
|
# Could offer different energy calculations e.g. Sobel or Scharr
|
||||||
energy = np.abs(np.gradient(ia, axis=0)) + np.abs(np.gradient(ia, axis=1))
|
energy = np.abs(np.gradient(ia, axis=0)) + np.abs(np.gradient(ia, axis=1))
|
||||||
|
|
||||||
# Find the starting position of the seam
|
# Find the starting position of the seam
|
||||||
@ -107,6 +111,7 @@ def seam_blend(ia1: np.ndarray, ia2: np.ndarray, blend_amount: int, x_seam: bool
|
|||||||
lowest_energy_line[max_y - 1] = np.argmin(res[max_y - 1, min_x : max_x - 1])
|
lowest_energy_line[max_y - 1] = np.argmin(res[max_y - 1, min_x : max_x - 1])
|
||||||
|
|
||||||
# Calc the path of the seam
|
# Calc the path of the seam
|
||||||
|
# could offer options for larger search than just 1 pixel by adjusting lpos and rpos
|
||||||
for ypos in range(max_y - 2, -1, -1):
|
for ypos in range(max_y - 2, -1, -1):
|
||||||
lowest_pos = lowest_energy_line[ypos + 1]
|
lowest_pos = lowest_energy_line[ypos + 1]
|
||||||
lpos = lowest_pos - 1
|
lpos = lowest_pos - 1
|
||||||
|
@ -371,8 +371,8 @@ def test_calc_tiles_min_overlap_difficult_size_div8():
|
|||||||
(128, 128, 128, 128, 127, False), # OK
|
(128, 128, 128, 128, 127, False), # OK
|
||||||
(128, 128, 128, 128, 0, False), # OK
|
(128, 128, 128, 128, 0, False), # OK
|
||||||
(128, 128, 64, 64, 0, False), # OK
|
(128, 128, 64, 64, 0, False), # OK
|
||||||
(128, 128, 129, 128, 0, True), # tile_height exceeds image_height.
|
(128, 128, 129, 128, 0, False), # tile_height exceeds image_height defaults to 1 tile.
|
||||||
(128, 128, 128, 129, 0, True), # tile_width exceeds image_width.
|
(128, 128, 128, 129, 0, False), # tile_width exceeds image_width defaults to 1 tile.
|
||||||
(128, 128, 64, 128, 64, True), # overlap equals tile_height.
|
(128, 128, 64, 128, 64, True), # overlap equals tile_height.
|
||||||
(128, 128, 128, 64, 64, True), # overlap equals tile_width.
|
(128, 128, 128, 64, 64, True), # overlap equals tile_width.
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user