Arrange images in a line. The interface resembles a CSS div with flexbox.
(
main_axis: Axis,
*images: Iterable[Float[Tensor, "channel _ _"]],
align: Alignment = "center",
gap: int = 8,
gap_color: Color = 1,
)
| 116 | |
| 117 | |
| 118 | def cat( |
| 119 | main_axis: Axis, |
| 120 | *images: Iterable[Float[Tensor, "channel _ _"]], |
| 121 | align: Alignment = "center", |
| 122 | gap: int = 8, |
| 123 | gap_color: Color = 1, |
| 124 | ) -> Float[Tensor, "channel height width"]: |
| 125 | """Arrange images in a line. The interface resembles a CSS div with flexbox.""" |
| 126 | device = images[0].device |
| 127 | gap_color = _sanitize_color(gap_color).to(device) |
| 128 | |
| 129 | # Find the maximum image side length in the cross axis dimension. |
| 130 | cross_dim = _get_cross_dim(main_axis) |
| 131 | cross_axis_length = max(image.shape[cross_dim] for image in images) |
| 132 | |
| 133 | # Pad the images. |
| 134 | padded_images = [] |
| 135 | for image in images: |
| 136 | # Create an empty image with the correct size. |
| 137 | padded_shape = list(image.shape) |
| 138 | padded_shape[cross_dim] = cross_axis_length |
| 139 | base = torch.ones(padded_shape, dtype=torch.float32, device=device) |
| 140 | base = base * gap_color[:, None, None] |
| 141 | padded_images.append(overlay(base, image, main_axis, "start", align)) |
| 142 | |
| 143 | # Intersperse separators if necessary. |
| 144 | if gap > 0: |
| 145 | # Generate a separator. |
| 146 | c, _, _ = images[0].shape |
| 147 | separator_size = [gap, gap] |
| 148 | separator_size[cross_dim - 1] = cross_axis_length |
| 149 | separator = torch.ones((c, *separator_size), dtype=torch.float32, device=device) |
| 150 | separator = separator * gap_color[:, None, None] |
| 151 | |
| 152 | # Intersperse the separator between the images. |
| 153 | padded_images = list(_intersperse(padded_images, separator)) |
| 154 | |
| 155 | return torch.cat(padded_images, dim=_get_main_dim(main_axis)) |
| 156 | |
| 157 | |
| 158 | def hcat( |
no test coverage detected