Spaces:
Build error
Build error
File size: 7,898 Bytes
c8c12e9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
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
|