mirror of
https://github.com/huggingface/lerobot.git
synced 2026-07-26 19:26:16 +00:00
fix(vlabench): bulletproof camera obs coercion to (h, w, 3) uint8
Previous resize path only kicked in when shape[:2] mismatched, so arrays with wrong channel count or unexpected layouts (e.g. HWC arriving as HWC but treated as CHW and transposed into junk shape) could still slip through. New _to_hwc3 helper: - strips leading singleton batch dims - auto-detects CHW vs HWC via channel size - normalizes 1/4-channel to 3 channels - resizes to (h, w) and casts to uint8 unconditionally Made-with: Cursor
This commit is contained in:
@@ -216,37 +216,51 @@ class VLABenchEnv(gym.Env):
|
|||||||
assert self._env is not None
|
assert self._env is not None
|
||||||
|
|
||||||
obs = self._env.get_observation()
|
obs = self._env.get_observation()
|
||||||
|
h, w = self.render_resolution
|
||||||
|
|
||||||
|
def _to_hwc3(arr: np.ndarray) -> np.ndarray:
|
||||||
|
"""Coerce any camera array to the declared (h, w, 3) uint8 shape."""
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
a = np.asarray(arr)
|
||||||
|
# Drop a leading singleton batch dim if present.
|
||||||
|
while a.ndim > 3 and a.shape[0] == 1:
|
||||||
|
a = a[0]
|
||||||
|
if a.ndim == 3 and a.shape[0] in (1, 3, 4) and a.shape[-1] not in (1, 3, 4):
|
||||||
|
# CHW → HWC
|
||||||
|
a = np.transpose(a, (1, 2, 0))
|
||||||
|
if a.ndim == 2:
|
||||||
|
a = np.stack([a] * 3, axis=-1)
|
||||||
|
if a.ndim != 3:
|
||||||
|
return np.zeros((h, w, 3), dtype=np.uint8)
|
||||||
|
# Force 3 channels.
|
||||||
|
if a.shape[-1] == 1:
|
||||||
|
a = np.repeat(a, 3, axis=-1)
|
||||||
|
elif a.shape[-1] == 4:
|
||||||
|
a = a[..., :3]
|
||||||
|
elif a.shape[-1] != 3:
|
||||||
|
return np.zeros((h, w, 3), dtype=np.uint8)
|
||||||
|
if a.shape[:2] != (h, w):
|
||||||
|
a = cv2.resize(a, (w, h), interpolation=cv2.INTER_AREA)
|
||||||
|
return a.astype(np.uint8)
|
||||||
|
|
||||||
# Extract camera images — VLABench returns (n_cameras, C, H, W) or individual arrays
|
# Extract camera images — VLABench returns (n_cameras, C, H, W) or individual arrays
|
||||||
images = {}
|
raw_frames: list[np.ndarray] = []
|
||||||
if "rgb" in obs:
|
if "rgb" in obs:
|
||||||
rgb = obs["rgb"]
|
rgb = obs["rgb"]
|
||||||
if isinstance(rgb, np.ndarray):
|
if isinstance(rgb, np.ndarray):
|
||||||
if rgb.ndim == 4:
|
if rgb.ndim == 4:
|
||||||
# (n_cameras, C, H, W) → transpose each to (H, W, C)
|
raw_frames = [rgb[i] for i in range(rgb.shape[0])]
|
||||||
if rgb.shape[0] >= 1:
|
|
||||||
images["image"] = np.transpose(rgb[0], (1, 2, 0)).astype(np.uint8)
|
|
||||||
if rgb.shape[0] >= 2:
|
|
||||||
images["second_image"] = np.transpose(rgb[1], (1, 2, 0)).astype(np.uint8)
|
|
||||||
if rgb.shape[0] >= 3:
|
|
||||||
images["wrist_image"] = np.transpose(rgb[2], (1, 2, 0)).astype(np.uint8)
|
|
||||||
elif rgb.ndim == 3:
|
elif rgb.ndim == 3:
|
||||||
# Single camera (C, H, W) or (H, W, C)
|
raw_frames = [rgb]
|
||||||
if rgb.shape[0] == 3: # CHW
|
|
||||||
images["image"] = np.transpose(rgb, (1, 2, 0)).astype(np.uint8)
|
|
||||||
else: # HWC
|
|
||||||
images["image"] = rgb.astype(np.uint8)
|
|
||||||
|
|
||||||
# VLABench's native render size may not match our declared observation_space.
|
image_keys = ["image", "second_image", "wrist_image"]
|
||||||
# Resize each image to (h, w) so gymnasium's vector env concatenate succeeds.
|
images: dict[str, np.ndarray] = {}
|
||||||
h, w = self.render_resolution
|
for i, key in enumerate(image_keys):
|
||||||
for key in ["image", "second_image", "wrist_image"]:
|
if i < len(raw_frames):
|
||||||
if key not in images:
|
images[key] = _to_hwc3(raw_frames[i])
|
||||||
|
else:
|
||||||
images[key] = np.zeros((h, w, 3), dtype=np.uint8)
|
images[key] = np.zeros((h, w, 3), dtype=np.uint8)
|
||||||
elif images[key].shape[:2] != (h, w):
|
|
||||||
import cv2
|
|
||||||
|
|
||||||
images[key] = cv2.resize(images[key], (w, h), interpolation=cv2.INTER_AREA).astype(np.uint8)
|
|
||||||
|
|
||||||
# Extract end-effector state — coerce to exactly (7,) so vector env concat
|
# Extract end-effector state — coerce to exactly (7,) so vector env concat
|
||||||
# doesn't fail with shape-mismatch on buffer np.stack.
|
# doesn't fail with shape-mismatch on buffer np.stack.
|
||||||
|
|||||||
Reference in New Issue
Block a user