| """Visualization utility functions.""" |
|
|
| import colorsys |
| import random |
| from typing import List, Optional, Sequence, Tuple |
|
|
| import numpy as np |
|
|
|
|
| |
| def get_colors(num_colors: int) -> List[Tuple[int, int, int]]: |
| """Gets colormap for points.""" |
| colors = [] |
| for i in np.arange(0.0, 360.0, 360.0 / num_colors): |
| hue = i / 360.0 |
| lightness = (50 + np.random.rand() * 10) / 100.0 |
| saturation = (90 + np.random.rand() * 10) / 100.0 |
| color = colorsys.hls_to_rgb(hue, lightness, saturation) |
| colors.append( |
| (int(color[0] * 255), int(color[1] * 255), int(color[2] * 255)) |
| ) |
| random.shuffle(colors) |
| return colors |
|
|
|
|
| def paint_point_track( |
| frames: np.ndarray, |
| point_tracks: np.ndarray, |
| visibles: np.ndarray, |
| colormap: Optional[List[Tuple[int, int, int]]] = None, |
| ) -> np.ndarray: |
| """Converts a sequence of points to color code video. |
| |
| Args: |
| frames: [num_frames, height, width, 3], np.uint8, [0, 255] |
| point_tracks: [num_points, num_frames, 2], np.float32, [0, width / height] |
| visibles: [num_points, num_frames], bool |
| colormap: colormap for points, each point has a different RGB color. |
| |
| Returns: |
| video: [num_frames, height, width, 3], np.uint8, [0, 255] |
| """ |
| num_points, num_frames = point_tracks.shape[0:2] |
| if colormap is None: |
| colormap = get_colors(num_colors=num_points) |
| height, width = frames.shape[1:3] |
| dot_size_as_fraction_of_min_edge = 0.015 |
| radius = int(round(min(height, width) * dot_size_as_fraction_of_min_edge)) |
| diam = radius * 2 + 1 |
| quadratic_y = np.square(np.arange(diam)[:, np.newaxis] - radius - 1) |
| quadratic_x = np.square(np.arange(diam)[np.newaxis, :] - radius - 1) |
| icon = (quadratic_y + quadratic_x) - (radius**2) / 2.0 |
| sharpness = 0.15 |
| icon = np.clip(icon / (radius * 2 * sharpness), 0, 1) |
| icon = 1 - icon[:, :, np.newaxis] |
| icon1 = np.pad(icon, [(0, 1), (0, 1), (0, 0)]) |
| icon2 = np.pad(icon, [(1, 0), (0, 1), (0, 0)]) |
| icon3 = np.pad(icon, [(0, 1), (1, 0), (0, 0)]) |
| icon4 = np.pad(icon, [(1, 0), (1, 0), (0, 0)]) |
|
|
| video = frames.copy() |
| for t in range(num_frames): |
| |
| image = np.pad( |
| video[t], |
| [ |
| (radius + 1, radius + 1), |
| (radius + 1, radius + 1), |
| (0, 0), |
| ], |
| ) |
| for i in range(num_points): |
| |
| |
| |
| |
| |
| x, y = point_tracks[i, t, :] + 0.5 |
| x = min(max(x, 0.0), width) |
| y = min(max(y, 0.0), height) |
|
|
| if visibles[i, t]: |
| x1, y1 = np.floor(x).astype(np.int32), np.floor(y).astype(np.int32) |
| x2, y2 = x1 + 1, y1 + 1 |
|
|
| |
| patch = ( |
| icon1 * (x2 - x) * (y2 - y) |
| + icon2 * (x2 - x) * (y - y1) |
| + icon3 * (x - x1) * (y2 - y) |
| + icon4 * (x - x1) * (y - y1) |
| ) |
| x_ub = x1 + 2 * radius + 2 |
| y_ub = y1 + 2 * radius + 2 |
| image[y1:y_ub, x1:x_ub, :] = (1 - patch) * image[ |
| y1:y_ub, x1:x_ub, : |
| ] + patch * np.array(colormap[i])[np.newaxis, np.newaxis, :] |
|
|
| |
| video[t] = image[ |
| radius + 1 : -radius - 1, radius + 1 : -radius - 1 |
| ].astype(np.uint8) |
| return video |
|
|
|
|