Spaces:
Build error
Build error
from typing import List, Tuple | |
import numpy as np | |
from skimage.draw import polygon | |
def random_square_patch(input_region: List[int], min_width: int = 10) -> List[int]: | |
"""Gets a random patch in the input region. | |
Args: | |
input_region (List[int]): Coordinates of the input region. [x1, y1, x2, y2] | |
min_width (int): Minimum width of the returned patch. | |
Example: | |
>>> image = np.zeros((200,200,3)) | |
>>> x1, y1, x2, y2 = random_square_patch([100,100,200,200]) | |
>>> patched = image.copy() | |
>>> patched[y1:y2, x1:x2, :] = 1 | |
>>> plt.imshow(patched) | |
Returns: | |
List[int]: Random square patch [x1, y1, x2, y2] | |
""" | |
x1_i, y1_i, x2_i, y2_i = input_region | |
cx, cy = np.random.randint(x1_i, x2_i), np.random.randint(y1_i, y2_i) | |
shortest_dim = min(x2_i - x1_i, y2_i - y1_i) | |
# make sure that shortest_dim is larger than min_width | |
shortest_dim = max(shortest_dim, min_width + 1) | |
rand_half_width = np.random.randint(min_width, shortest_dim) // 2 | |
x1, y1, x2, y2 = cx - rand_half_width, cy - rand_half_width, cx + rand_half_width, cy + rand_half_width | |
# border check | |
if x1 < 0: | |
x1 = 0 | |
x2 = 2 * rand_half_width | |
elif x2 > x2_i: | |
x2 = x2_i | |
x1 = x2_i - 2 * rand_half_width | |
if y1 < 0: | |
y1 = 0 | |
y2 = 2 * rand_half_width | |
elif y2 > y2_i: | |
y2 = y2_i | |
y1 = y2_i - 2 * rand_half_width | |
return [x1, y1, x2, y2] | |
def triangle(input_region: List[int]) -> Tuple[List[int], List[int]]: | |
"""Get coordinates of points inside a triangle. | |
Args: | |
input_region (List[int]): Region in which to draw the triangle. [x1, y1, x2, y2] | |
Example: | |
>>> image = np.full((200,200,3),fill_value=255, dtype=np.uint8) | |
>>> patch_region = random_square_patch([100, 100, 200, 200]) | |
>>> xx, yy = triangle(patch_region) | |
>>> patched = image.copy() | |
>>> patched[yy, xx, :] = 1 | |
>>> plt.imshow(patched) | |
Returns: | |
Tuple[List[int], List[int]]: Array of cols and rows which denote the mask. | |
""" | |
x1_i, y1_i, x2_i, y2_i = input_region | |
x1, y1 = x1_i + (x2_i - x1_i) // 2, y1_i | |
x2, y2 = x1_i, y2_i | |
x3, y3 = x2_i, y2_i | |
return polygon([x1, x2, x3], [y1, y2, y3]) | |
def rectangle(input_region: List[int], min_side: int = 10) -> Tuple[List[int], List[int]]: | |
"""Get coordinates of corners of a rectangle. Only vertical rectangles are | |
generated. | |
Args: | |
input_region (List[int]): Region in which to draw the rectangle. [x1, y1, x2, y2] | |
min_side (int, optional): Minimum side of the rectangle. Defaults to 10. | |
Example: | |
>>> image = np.full((200,200,3),fill_value=255, dtype=np.uint8) | |
>>> patch_region = random_square_patch([100, 100, 200, 200]) | |
>>> x1, y1, x2, y2 = rectangle(patch_region) | |
>>> patched = image.copy() | |
>>> patched[y1:y2, x1:x2, :] = 1 | |
>>> plt.imshow(patched) | |
Returns: | |
Tuple[List[int], List[int]]: Random rectangle region. [x1, y1, x2, y2] | |
""" | |
x1_i, y1, x2_i, y2 = input_region | |
shortest_dim = min(x2_i - x1_i, y2 - y1) | |
# make sure that shortest_dim is larger than min_side | |
shortest_dim = max(shortest_dim, min_side + 1) | |
cx = (x2_i - x1_i) // 2 | |
rand_half_width = np.random.randint(min_side, shortest_dim) // 2 | |
x1 = cx - rand_half_width | |
x2 = cx + rand_half_width | |
xs = np.arange(x1, x2, 1) | |
ys = np.arange(y1, y2, 1) | |
yy, xx = np.meshgrid(ys, xs, sparse=True) | |
return xx, yy | |
def hexagon(input_region: List[int]) -> Tuple[List[int], List[int]]: | |
"""Get coordinates of points inside a hexagon. | |
Args: | |
input_region (List[int]): Region in which to draw the hexagon. [x1, y1, x2, y2] | |
Example: | |
>>> image = np.full((200,200,3),fill_value=255, dtype=np.uint8) | |
>>> patch_region = random_square_patch([100, 100, 200, 200]) | |
>>> xx, yy = hexagon(patch_region) | |
>>> patched = image.copy() | |
>>> patched[yy, xx, :] = 1 | |
>>> plt.imshow(patched) | |
Returns: | |
Tuple[List[int], List[int]]: Array of cols and rows which denote the mask. | |
""" | |
x1_i, y1_i, x2_i, _ = input_region | |
cx = (x2_i - x1_i) // 2 | |
hex_half_side = (x2_i - x1_i) // 4 # assume side of hexagon to be 1/2 of the square size | |
x1, y1 = x1_i + hex_half_side, y1_i | |
x2, y2 = x1_i + cx + hex_half_side, y1_i | |
x3, y3 = x2_i, y1_i + int(1.732 * hex_half_side) # 2cos(30) | |
x4, y4 = x1_i + cx + hex_half_side, y1_i + int(3.4641 * hex_half_side) # 4 * cos(30) | |
x5, y5 = x1_i + hex_half_side, y1_i + int(3.4641 * hex_half_side) # 4 * cos(30) | |
x6, y6 = x1_i, y1_i + int(1.732 * hex_half_side) | |
return polygon([x1, x2, x3, x4, x5, x6], [y1, y2, y3, y4, y5, y6]) | |
def star(input_region: List[int]) -> Tuple[List[int], List[int]]: | |
"""Get coordinates of points inside a star. | |
Args: | |
input_region (List[int]): Region in which to draw the star. [x1, y1, x2, y2] | |
Example: | |
>>> image = np.full((200,200,3),fill_value=255, dtype=np.uint8) | |
>>> patch_region = random_square_patch([100, 100, 200, 200]) | |
>>> xx, yy = star(patch_region) | |
>>> patched = image.copy() | |
>>> patched[yy, xx, :] = 1 | |
>>> plt.imshow(patched) | |
Returns: | |
Tuple[List[int], List[int]]: Array of cols and rows which denote the mask. | |
""" | |
x1_i, y1_i, x2_i, y2_i = input_region | |
outer_dim = (x2_i - x1_i) // 2 | |
inner_dim = (x2_i - x1_i) // 4 | |
cx = x1_i + (x2_i - x1_i) // 2 | |
cy = y1_i + (y2_i - y1_i) // 2 | |
x1, y1 = cx + int(outer_dim * np.cos(0.314159)), cy + int(outer_dim * np.sin(0.314159)) | |
x2, y2 = cx + int(inner_dim * np.cos(0.942478)), cy + int(inner_dim * np.sin(0.942478)) | |
x3, y3 = cx + int(outer_dim * np.cos(1.5708)), cy + int(outer_dim * np.sin(1.5708)) | |
x4, y4 = cx + int(inner_dim * np.cos(2.19911)), cy + int(inner_dim * np.sin(2.19911)) | |
x5, y5 = cx + int(outer_dim * np.cos(2.82743)), cy + int(outer_dim * np.sin(2.82743)) | |
x6, y6 = cx + int(inner_dim * np.cos(3.45575)), cy + int(inner_dim * np.sin(3.45575)) | |
x7, y7 = cx + int(outer_dim * np.cos(4.08407)), cy + int(outer_dim * np.sin(4.08407)) | |
x8, y8 = cx, cy - inner_dim | |
x9, y9 = cx + int(outer_dim * np.cos(5.34071)), cy + int(outer_dim * np.sin(5.34071)) | |
x10, y10 = cx + int(inner_dim * np.cos(5.96903)), cy + int(inner_dim * np.sin(5.96903)) | |
print([x1, x2, x3, x4, x5, x6, x7, x8, x9, x10], [y1, y2, y3, y4, y5, y6, y7, y8, y9, y10]) | |
return polygon([x1, x2, x3, x4, x5, x6, x7, x8, x9, x10], [y1, y2, y3, y4, y5, y6, y7, y8, y9, y10]) | |
def random_shapes( | |
input_region: List[int], size: Tuple[int, int], max_shapes: int, shape: str = "rectangle" | |
) -> np.ndarray: | |
"""Generate image with random shape. | |
Args: | |
input_region (List[int]): Coordinates of the input region. [x1, y1, x2, y2] | |
size (Tuple[int, int]): Size of the input image | |
max_shapes (int): Maximum number of shapes of a certain kind to draw | |
shape (str): Name of the shape. Defaults to rectangle | |
Returns: | |
np.ndarray: Image containing the shape | |
""" | |
shape_fn: Tuple[List[int], List[int]] | |
if shape == "rectangle": | |
shape_fn = rectangle | |
elif shape == "triangle": | |
shape_fn = triangle | |
elif shape == "hexagon": | |
shape_fn = hexagon | |
elif shape == "star": | |
shape_fn = star | |
else: | |
raise ValueError(f"Shape function {shape} not supported!") | |
shape_image: np.ndarray = np.full((*size, 3), fill_value=255, dtype=np.uint8) | |
for _ in range(max_shapes): | |
image = np.full((*size, 3), fill_value=255, dtype=np.uint8) | |
patch_region = random_square_patch(input_region) | |
xx, yy = shape_fn(patch_region) | |
# assign random colour | |
image[yy, xx, :] = (np.random.randint(0, 255), np.random.randint(0, 255), np.random.randint(0, 255)) | |
shape_image = np.minimum(image, shape_image) # since 255 is max | |
return shape_image | |