Module src.app.GraphLayout.LayoutComposition
Source code
from src.app.Module import Module
import matplotlib.pyplot as plt
import matplotlib.transforms as transforms
import numpy as np
import cv2
class LayoutComposition(Module):
"""Composes the final image.
This class uses the results of layout modules to create the final render.
To render the image a raycasting like technique is used to find the closest salient region for
each pixel in the final image. The corresponding pixel value is then applied at that point.
Attributes:
_delta: Delta padding to use to compose(draw) salient regions in a cluster (float)
_out_size: Size (in pixels) of the resulting image (int)
"""
def __init__(self, prev_module, delta, out_size):
super().__init__('LayoutComposition', prev_module)
self._delta = delta
self._out_size = out_size
def run(self):
super().run()
image = np.zeros((self._out_size, self._out_size, 3), dtype=np.uint8)
num_cells = len(self._data['cells'])
print('0 of {} cells rendered'.format(num_cells))
for i, cell in enumerate(self._data['cells']):
self.process_cell(image, cell)
print('{} of {} cells rendered'.format(i+1, num_cells))
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
self._result = image
def process_cell(self, image, cell):
"""Processes a single voronoi cell of the final render.
Pixels for the current cell are determined. For each pixel the corresponding image is found and
the pixel value of that image at that point is applied to the final render.
Args:
image: Image to apply changes to (numpy/cv2 image)
cell: Cell object to process (object)
"""
# Get and rescale images
scale = cell['scale']
images = cell['images']
self.rescale_images(images, scale)
# Get and rescale coordinates and bounding polygon
coordinates = cell['coordinates'] * self._out_size
bounding_poly = cell['bounding_poly'].transformed(transforms.Affine2D().scale(self._out_size))
extents = bounding_poly.get_extents()
x0 = int(extents.xmin)
x1 = int(extents.xmax)
y0 = int(extents.ymin)
y1 = int(extents.ymax)
# Iterate over all pixels in the cell
for x in range(x0, x1):
for y in range(y0, y1):
# Ignore pixels outside the polygon boundary
if not bounding_poly.contains_point([x,y]):
continue
# Find the closest circle
i = self.nearest_circle([x, y], coordinates)
# Get the pixel color of the corresponding image
image[y, x] = self.get_pixel([x, y], images[i], coordinates[i])
def nearest_circle(self, point, coordinates):
"""Finds the closest circle to a arbitrary point in a single cell.
Since saliency radii are based on the original images' size we need to scale them
to fit the 0-1 region of the final image.
A good measure for scale was determined empirically.
Args:
point: Point to search from (list of ints)
coordinates: Coordinates of salient regions (list of lists of floats)
Returns:
The id of the closest circle (salient region) in coordinates
"""
least = -1
least_id = -1
for i, coord in enumerate(coordinates):
dist = np.linalg.norm(point - coord[0:2]) - (coord[2]+self._delta)
if dist < least or least == -1:
least = dist
least_id = i
return least_id
def rescale_images(self, images, scale):
"""Scales images to appropriate size for the final rendering.
Args:
images: List of images to rescale (list of numpy/cv2 images)
scale: Scale to use - determined at layout time (float)
"""
for i in range(len(images)):
image_scale = scale * self._out_size
images[i] = cv2.resize(images[i], None, fx=image_scale, fy=image_scale)
def get_pixel(self, point, image, coordinate):
"""Gets image pixel value at a certain coordinate.
This method determines appropriate offsets and then gets the pixel value of an image a point.
If point lies outside the image region, a default color is returned.
Args:
point: Point to sample at (list of ints)
image: Images to sample from (numpy/cv2 image)
coordinate: Coordinate of salient region (list of floats)
Returns:
The id of the closest circle (salient region) in coordinates
"""
image_coordinate = np.floor(point - coordinate[3:5]).astype(np.int)
if np.min(image_coordinate) < 0 or np.greater_equal(image_coordinate[::-1], image.shape[:2]).any():
return (255,255,255)
return image[image_coordinate[1], image_coordinate[0], :]
def visualize(self):
result = self.get_module_results()
fig, ax = plt.subplots()
ax.axis('off')
plt.xlim((0, 1))
plt.ylim((0, 1))
plt.imshow(result, origin='upper', extent=[0, 1, 0, 1])
plt.show()
Classes
class LayoutComposition (prev_module, delta, out_size)
-
Composes the final image.
This class uses the results of layout modules to create the final render. To render the image a raycasting like technique is used to find the closest salient region for each pixel in the final image. The corresponding pixel value is then applied at that point.
Attributes
_delta
- Delta padding to use to compose(draw) salient regions in a cluster (float)
_out_size
- Size (in pixels) of the resulting image (int)
Source code
class LayoutComposition(Module): """Composes the final image. This class uses the results of layout modules to create the final render. To render the image a raycasting like technique is used to find the closest salient region for each pixel in the final image. The corresponding pixel value is then applied at that point. Attributes: _delta: Delta padding to use to compose(draw) salient regions in a cluster (float) _out_size: Size (in pixels) of the resulting image (int) """ def __init__(self, prev_module, delta, out_size): super().__init__('LayoutComposition', prev_module) self._delta = delta self._out_size = out_size def run(self): super().run() image = np.zeros((self._out_size, self._out_size, 3), dtype=np.uint8) num_cells = len(self._data['cells']) print('0 of {} cells rendered'.format(num_cells)) for i, cell in enumerate(self._data['cells']): self.process_cell(image, cell) print('{} of {} cells rendered'.format(i+1, num_cells)) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) self._result = image def process_cell(self, image, cell): """Processes a single voronoi cell of the final render. Pixels for the current cell are determined. For each pixel the corresponding image is found and the pixel value of that image at that point is applied to the final render. Args: image: Image to apply changes to (numpy/cv2 image) cell: Cell object to process (object) """ # Get and rescale images scale = cell['scale'] images = cell['images'] self.rescale_images(images, scale) # Get and rescale coordinates and bounding polygon coordinates = cell['coordinates'] * self._out_size bounding_poly = cell['bounding_poly'].transformed(transforms.Affine2D().scale(self._out_size)) extents = bounding_poly.get_extents() x0 = int(extents.xmin) x1 = int(extents.xmax) y0 = int(extents.ymin) y1 = int(extents.ymax) # Iterate over all pixels in the cell for x in range(x0, x1): for y in range(y0, y1): # Ignore pixels outside the polygon boundary if not bounding_poly.contains_point([x,y]): continue # Find the closest circle i = self.nearest_circle([x, y], coordinates) # Get the pixel color of the corresponding image image[y, x] = self.get_pixel([x, y], images[i], coordinates[i]) def nearest_circle(self, point, coordinates): """Finds the closest circle to a arbitrary point in a single cell. Since saliency radii are based on the original images' size we need to scale them to fit the 0-1 region of the final image. A good measure for scale was determined empirically. Args: point: Point to search from (list of ints) coordinates: Coordinates of salient regions (list of lists of floats) Returns: The id of the closest circle (salient region) in coordinates """ least = -1 least_id = -1 for i, coord in enumerate(coordinates): dist = np.linalg.norm(point - coord[0:2]) - (coord[2]+self._delta) if dist < least or least == -1: least = dist least_id = i return least_id def rescale_images(self, images, scale): """Scales images to appropriate size for the final rendering. Args: images: List of images to rescale (list of numpy/cv2 images) scale: Scale to use - determined at layout time (float) """ for i in range(len(images)): image_scale = scale * self._out_size images[i] = cv2.resize(images[i], None, fx=image_scale, fy=image_scale) def get_pixel(self, point, image, coordinate): """Gets image pixel value at a certain coordinate. This method determines appropriate offsets and then gets the pixel value of an image a point. If point lies outside the image region, a default color is returned. Args: point: Point to sample at (list of ints) image: Images to sample from (numpy/cv2 image) coordinate: Coordinate of salient region (list of floats) Returns: The id of the closest circle (salient region) in coordinates """ image_coordinate = np.floor(point - coordinate[3:5]).astype(np.int) if np.min(image_coordinate) < 0 or np.greater_equal(image_coordinate[::-1], image.shape[:2]).any(): return (255,255,255) return image[image_coordinate[1], image_coordinate[0], :] def visualize(self): result = self.get_module_results() fig, ax = plt.subplots() ax.axis('off') plt.xlim((0, 1)) plt.ylim((0, 1)) plt.imshow(result, origin='upper', extent=[0, 1, 0, 1]) plt.show()
Ancestors
Methods
def get_pixel(self, point, image, coordinate)
-
Gets image pixel value at a certain coordinate.
This method determines appropriate offsets and then gets the pixel value of an image a point. If point lies outside the image region, a default color is returned.
Args
point
- Point to sample at (list of ints)
image
- Images to sample from (numpy/cv2 image)
coordinate
- Coordinate of salient region (list of floats)
Returns
The
id
ofthe
closest
circle
(salient
region
)in
coordinates
Source code
def get_pixel(self, point, image, coordinate): """Gets image pixel value at a certain coordinate. This method determines appropriate offsets and then gets the pixel value of an image a point. If point lies outside the image region, a default color is returned. Args: point: Point to sample at (list of ints) image: Images to sample from (numpy/cv2 image) coordinate: Coordinate of salient region (list of floats) Returns: The id of the closest circle (salient region) in coordinates """ image_coordinate = np.floor(point - coordinate[3:5]).astype(np.int) if np.min(image_coordinate) < 0 or np.greater_equal(image_coordinate[::-1], image.shape[:2]).any(): return (255,255,255) return image[image_coordinate[1], image_coordinate[0], :]
def nearest_circle(self, point, coordinates)
-
Finds the closest circle to a arbitrary point in a single cell.
Since saliency radii are based on the original images' size we need to scale them to fit the 0-1 region of the final image. A good measure for scale was determined empirically.
Args
point
- Point to search from (list of ints)
coordinates
- Coordinates of salient regions (list of lists of floats)
Returns
The
id
ofthe
closest
circle
(salient
region
)in
coordinates
Source code
def nearest_circle(self, point, coordinates): """Finds the closest circle to a arbitrary point in a single cell. Since saliency radii are based on the original images' size we need to scale them to fit the 0-1 region of the final image. A good measure for scale was determined empirically. Args: point: Point to search from (list of ints) coordinates: Coordinates of salient regions (list of lists of floats) Returns: The id of the closest circle (salient region) in coordinates """ least = -1 least_id = -1 for i, coord in enumerate(coordinates): dist = np.linalg.norm(point - coord[0:2]) - (coord[2]+self._delta) if dist < least or least == -1: least = dist least_id = i return least_id
def process_cell(self, image, cell)
-
Processes a single voronoi cell of the final render.
Pixels for the current cell are determined. For each pixel the corresponding image is found and the pixel value of that image at that point is applied to the final render.
Args
image
- Image to apply changes to (numpy/cv2 image)
cell
- Cell object to process (object)
Source code
def process_cell(self, image, cell): """Processes a single voronoi cell of the final render. Pixels for the current cell are determined. For each pixel the corresponding image is found and the pixel value of that image at that point is applied to the final render. Args: image: Image to apply changes to (numpy/cv2 image) cell: Cell object to process (object) """ # Get and rescale images scale = cell['scale'] images = cell['images'] self.rescale_images(images, scale) # Get and rescale coordinates and bounding polygon coordinates = cell['coordinates'] * self._out_size bounding_poly = cell['bounding_poly'].transformed(transforms.Affine2D().scale(self._out_size)) extents = bounding_poly.get_extents() x0 = int(extents.xmin) x1 = int(extents.xmax) y0 = int(extents.ymin) y1 = int(extents.ymax) # Iterate over all pixels in the cell for x in range(x0, x1): for y in range(y0, y1): # Ignore pixels outside the polygon boundary if not bounding_poly.contains_point([x,y]): continue # Find the closest circle i = self.nearest_circle([x, y], coordinates) # Get the pixel color of the corresponding image image[y, x] = self.get_pixel([x, y], images[i], coordinates[i])
def rescale_images(self, images, scale)
-
Scales images to appropriate size for the final rendering.
Args
images
- List of images to rescale (list of numpy/cv2 images)
scale
- Scale to use - determined at layout time (float)
Source code
def rescale_images(self, images, scale): """Scales images to appropriate size for the final rendering. Args: images: List of images to rescale (list of numpy/cv2 images) scale: Scale to use - determined at layout time (float) """ for i in range(len(images)): image_scale = scale * self._out_size images[i] = cv2.resize(images[i], None, fx=image_scale, fy=image_scale)
Inherited members