File size: 1,787 Bytes
6364f97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Frame preprocessing identical to ``dataset.LiberoHDF5Dataset._to_tensor``.

Verbatim port of the reference transform. LIBERO stores every camera (including the wrist
camera) rotated by 180 degrees; the reference dataset rights them with ``x[:, ::-1, ::-1]``
applied to the ``[n, H, W, C]`` array *before* any other op.

The example PNGs shipped with this Space were exported from the demonstrations with that
rotation already applied, so the app passes ``rotate=False`` for them; set it to ``True`` (the
reference default) for raw, as-stored LIBERO frames.
"""

from __future__ import annotations

from typing import Sequence, Tuple

import numpy as np
import torch
import torch.nn.functional as F

IMAGE_SIZE: Tuple[int, int] = (128, 128)
ROTATE_180: bool = True


def to_tensor(raw: np.ndarray, rotate: bool = ROTATE_180) -> torch.Tensor:
    """``[H, W, C]`` or ``[n, H, W, C]`` -> ``[C, H', W']`` / ``[n, C, H', W']`` float32 in [0, 1]."""
    x = np.asarray(raw)
    single = x.ndim == 3
    if single:
        x = x[None]
    # the rotate must happen *before* every other op, exactly like the dataset does
    if rotate:
        x = x[:, ::-1, ::-1]
    out = torch.from_numpy(np.ascontiguousarray(x)).permute(0, 3, 1, 2).to(torch.float32)
    if x.dtype == np.uint8:
        out = out / 255.0
    if IMAGE_SIZE is not None and tuple(out.shape[-2:]) != IMAGE_SIZE:
        out = F.interpolate(out, size=IMAGE_SIZE, mode="bilinear", align_corners=False, antialias=True)
    return out[0] if single else out


def to_views(frames: Sequence[np.ndarray], rotate: bool = ROTATE_180) -> torch.Tensor:
    """One frame per camera -> ``[V, C, H, W]`` in the order given (the checkpoint's ``camera_keys``)."""
    return torch.stack([to_tensor(f, rotate=rotate) for f in frames], dim=0)