Create sprites upsampled, before downsampling so they hhave a smoother edge interpolation
This commit is contained in:
parent
fa249a0f24
commit
99f7802195
1 changed files with 19 additions and 8 deletions
|
|
@ -44,6 +44,10 @@ BG_COLOR = [220, 215, 217]
|
||||||
RNG = np.random.default_rng()
|
RNG = np.random.default_rng()
|
||||||
|
|
||||||
DOWNSAMPLE = 2
|
DOWNSAMPLE = 2
|
||||||
|
# Upsample for sprites and then downsample to create sharp edges for each sprite
|
||||||
|
# as these are small and calculated once there is almos no performance penalty
|
||||||
|
# for a nice gain in quality.
|
||||||
|
SPRITE_UPSAMPLE = 4
|
||||||
|
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
|
|
@ -75,7 +79,7 @@ class SimulatedCamera(BaseCamera):
|
||||||
self,
|
self,
|
||||||
thing_server_interface: lt.ThingServerInterface,
|
thing_server_interface: lt.ThingServerInterface,
|
||||||
shape: tuple[int, int, int] = (616, 820, 3),
|
shape: tuple[int, int, int] = (616, 820, 3),
|
||||||
glyph_shape: tuple[int, int, int] = (121, 121, 3),
|
glyph_size: int = 121,
|
||||||
canvas_shape: tuple[int, int, int] = (3000, 4000, 3),
|
canvas_shape: tuple[int, int, int] = (3000, 4000, 3),
|
||||||
sample_limits: Optional[tuple[int, int]] = (1000, 1500),
|
sample_limits: Optional[tuple[int, int]] = (1000, 1500),
|
||||||
frame_interval: float = 0.1,
|
frame_interval: float = 0.1,
|
||||||
|
|
@ -83,7 +87,7 @@ class SimulatedCamera(BaseCamera):
|
||||||
"""Initialise the simulated with settings for how images are generated.
|
"""Initialise the simulated with settings for how images are generated.
|
||||||
|
|
||||||
:param shape: The shape (size) of the generated image.
|
:param shape: The shape (size) of the generated image.
|
||||||
:param glyph_shape: The size randomly positioned glyphs.
|
:param glyph_size: The size randomly positioned glyphs.
|
||||||
:param canvas_shape: The shape (size) of the canvas generated on initialisation
|
:param canvas_shape: The shape (size) of the canvas generated on initialisation
|
||||||
that images are cropped from. If this is too large the it uses resources,
|
that images are cropped from. If this is too large the it uses resources,
|
||||||
but its size limits the range of motion of the simulation.
|
but its size limits the range of motion of the simulation.
|
||||||
|
|
@ -96,7 +100,7 @@ class SimulatedCamera(BaseCamera):
|
||||||
super().__init__(thing_server_interface)
|
super().__init__(thing_server_interface)
|
||||||
self.shape = shape
|
self.shape = shape
|
||||||
self.ds_shape = _downsample_shape(shape)
|
self.ds_shape = _downsample_shape(shape)
|
||||||
self.glyph_shape = _downsample_shape(glyph_shape)
|
self.glyph_size = glyph_size // DOWNSAMPLE
|
||||||
self.canvas_shape = _downsample_shape(canvas_shape)
|
self.canvas_shape = _downsample_shape(canvas_shape)
|
||||||
sample_limits = canvas_shape[:2] if sample_limits is None else sample_limits
|
sample_limits = canvas_shape[:2] if sample_limits is None else sample_limits
|
||||||
self.sample_limits = _downsample_shape(sample_limits)
|
self.sample_limits = _downsample_shape(sample_limits)
|
||||||
|
|
@ -128,10 +132,11 @@ class SimulatedCamera(BaseCamera):
|
||||||
def generate_sprites(self) -> None:
|
def generate_sprites(self) -> None:
|
||||||
"""Generate sprites to populate the image."""
|
"""Generate sprites to populate the image."""
|
||||||
sprite_sizes = [10, 21, 36, 40, 50]
|
sprite_sizes = [10, 21, 36, 40, 50]
|
||||||
sprite_sizes = [s / DOWNSAMPLE for s in sprite_sizes]
|
sprite_sizes = [s * SPRITE_UPSAMPLE for s in sprite_sizes]
|
||||||
self.sprites = []
|
self.sprites = []
|
||||||
|
|
||||||
channel_block = np.zeros(self.glyph_shape[0:2])
|
block_size = self.glyph_size * DOWNSAMPLE * SPRITE_UPSAMPLE
|
||||||
|
channel_block = np.zeros((block_size, block_size))
|
||||||
x = np.arange(channel_block.shape[0])
|
x = np.arange(channel_block.shape[0])
|
||||||
y = np.arange(channel_block.shape[1])
|
y = np.arange(channel_block.shape[1])
|
||||||
# 2D grid of radii
|
# 2D grid of radii
|
||||||
|
|
@ -156,8 +161,14 @@ class SimulatedCamera(BaseCamera):
|
||||||
sprite_b[sprite_mask] = 70 * sprite_px
|
sprite_b[sprite_mask] = 70 * sprite_px
|
||||||
# Stack into a negative image of the sprite
|
# Stack into a negative image of the sprite
|
||||||
sprite = np.stack([sprite_r, sprite_g, sprite_b], axis=2)
|
sprite = np.stack([sprite_r, sprite_g, sprite_b], axis=2)
|
||||||
# Convert to uint8 and append to the list
|
# Convert to uint8
|
||||||
self.sprites.append(sprite.astype(np.uint8))
|
sprite = sprite.astype(np.uint8)
|
||||||
|
# Convert to PIL (and back) to resize then append to list of sprites
|
||||||
|
sprite_pil = Image.fromarray(sprite)
|
||||||
|
sprite_pil = sprite_pil.resize(
|
||||||
|
(self.glyph_size, self.glyph_size), Image.BILINEAR
|
||||||
|
)
|
||||||
|
self.sprites.append(np.array(sprite_pil))
|
||||||
|
|
||||||
def generate_blobs(self, n_blobs: int = 1000) -> None:
|
def generate_blobs(self, n_blobs: int = 1000) -> None:
|
||||||
"""Generate coordinates of blobs and their sizes, centered around (0,0).
|
"""Generate coordinates of blobs and their sizes, centered around (0,0).
|
||||||
|
|
@ -169,7 +180,7 @@ class SimulatedCamera(BaseCamera):
|
||||||
:param n_blobs: The number of blobs to generate.
|
:param n_blobs: The number of blobs to generate.
|
||||||
"""
|
"""
|
||||||
self.blobs = np.zeros((n_blobs, 3))
|
self.blobs = np.zeros((n_blobs, 3))
|
||||||
w = np.max(self.glyph_shape)
|
w = self.glyph_size
|
||||||
|
|
||||||
self.blobs[:, 0] = RNG.uniform(w // 2, self.sample_limits[1] - w // 2, n_blobs)
|
self.blobs[:, 0] = RNG.uniform(w // 2, self.sample_limits[1] - w // 2, n_blobs)
|
||||||
self.blobs[:, 1] = RNG.uniform(w // 2, self.sample_limits[0] - w // 2, n_blobs)
|
self.blobs[:, 1] = RNG.uniform(w // 2, self.sample_limits[0] - w // 2, n_blobs)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue