| import sys |
| import os |
| import argparse |
| import glob |
| import numpy as np |
| import pyarrow.parquet as pq |
| import imageio.v3 as iio |
| from pathlib import Path |
| from tqdm import tqdm |
| from lehome.utils.depth_to_pointcloud import generate_pointcloud_from_data |
|
|
|
|
| current_dir = os.path.dirname(os.path.abspath(__file__)) |
| project_root = os.path.abspath(os.path.join(current_dir, "../../..")) |
|
|
|
|
| def get_args(): |
| parser = argparse.ArgumentParser(description="Process Parquet depth and MP4 RGB into Pointclouds.") |
| parser.add_argument( |
| "--dataset_root", |
| type=str, |
| required=True, |
| help="Path to the dataset root, e.g., /path/to/lehome/Datasets/record/001" |
| ) |
| parser.add_argument( |
| "--num_points", |
| type=int, |
| default=4096, |
| help="Number of points per pointcloud" |
| ) |
| return parser.parse_args() |
|
|
| def main(): |
| args = get_args() |
| dataset_path = Path(args.dataset_root) |
|
|
| |
| |
| |
| |
| video_path = dataset_path / "videos" / "observation.images.top_rgb" / "chunk-000" / "file-000.mp4" |
| |
| if not video_path.exists(): |
| print(f"Error: Video file not found at {video_path}") |
| return |
|
|
| print(f"Found Master Video: {video_path}") |
|
|
| |
| |
| |
| parquet_dir = dataset_path / "data" / "chunk-000" |
| if not parquet_dir.exists(): |
| print(f"Error: Parquet directory not found at {parquet_dir}") |
| return |
|
|
| parquet_files = sorted(glob.glob(str(parquet_dir / "file-*.parquet"))) |
| |
| if not parquet_files: |
| print("No parquet files found.") |
| return |
|
|
| print(f"Found {len(parquet_files)} episode parquet files.") |
|
|
| |
| |
| |
| video_reader = iio.imiter(str(video_path), plugin="pyav") |
| video_iterator = iter(video_reader) |
|
|
| |
| |
| |
| total_frames_processed = 0 |
|
|
| for ep_idx, pq_file in enumerate(tqdm(parquet_files, desc="Processing Episodes")): |
| |
| |
| try: |
| table = pq.read_table(pq_file) |
| pydict = table.to_pydict() |
| |
| if "observation.top_depth" not in pydict: |
| print(f"Skipping {pq_file}: 'observation.top_depth' key not found.") |
| continue |
| |
| depth_list = pydict["observation.top_depth"] |
| num_frames_in_episode = len(depth_list) |
| |
| except Exception as e: |
| print(f"Error reading parquet {pq_file}: {e}") |
| continue |
|
|
| |
| output_dir = dataset_path / "pointclouds" / f"episode_{ep_idx:03d}" |
| output_dir.mkdir(parents=True, exist_ok=True) |
|
|
| |
| for frame_idx in range(num_frames_in_episode): |
| try: |
| rgb_frame = next(video_iterator) |
| |
| depth_data = depth_list[frame_idx] |
| |
| if isinstance(depth_data, list): |
| depth_frame = np.array(depth_data, dtype=np.float32) |
| else: |
| depth_frame = depth_data |
| |
| |
| if depth_frame.ndim == 1: |
| if depth_frame.size == 480 * 640: |
| depth_frame = depth_frame.reshape((480, 640)) |
| else: |
| print(f"Error: Depth frame size {depth_frame.size} does not match 480x640") |
| continue |
| |
| |
| depth_frame = depth_frame.astype(np.float32) / 1000.0 |
|
|
| pointclouds_with_color = generate_pointcloud_from_data( |
| rgb_image=rgb_frame, |
| depth_image=depth_frame, |
| num_points=args.num_points, |
| use_fps=True |
| ) |
|
|
| save_path = output_dir / f"frame_{frame_idx:06d}.npz" |
| np.savez_compressed(str(save_path), pointcloud=pointclouds_with_color) |
| |
| total_frames_processed += 1 |
|
|
| except StopIteration: |
| print(f"Error: Video ended unexpectedly at Episode {ep_idx}, Frame {frame_idx}!") |
| break |
| except Exception as e: |
| print(f"Error processing Ep {ep_idx} Frame {frame_idx}: {e}") |
| continue |
|
|
| print(f"\nAll done! Processed {total_frames_processed} frames across {len(parquet_files)} episodes.") |
|
|
| if __name__ == "__main__": |
| main() |
| |