| """ |
| ScanNet20 / ScanNet200 / ScanNet Data Efficient Dataset |
| |
| Author: Xiaoyang Wu (xiaoyang.wu.cs@gmail.com) |
| Please cite our work if the code is helpful to you. |
| """ |
|
|
| import os |
| import glob |
| import numpy as np |
| import torch |
| from copy import deepcopy |
| from torch.utils.data import Dataset |
| from collections.abc import Sequence |
|
|
| from pointcept.utils.logger import get_root_logger |
| from pointcept.utils.cache import shared_dict |
| from .builder import DATASETS |
| from .defaults import DefaultDataset |
| from .transform import Compose, TRANSFORMS |
| from .preprocessing.scannet.meta_data.scannet200_constants import ( |
| VALID_CLASS_IDS_20, |
| VALID_CLASS_IDS_200, |
| ) |
|
|
|
|
| @DATASETS.register_module() |
| class ScanNetDataset(DefaultDataset): |
| VALID_ASSETS = [ |
| "coord", |
| "color", |
| "normal", |
| "segment20", |
| "instance", |
| ] |
| class2id = np.array(VALID_CLASS_IDS_20) |
|
|
| def __init__( |
| self, |
| lr_file=None, |
| la_file=None, |
| split="train", |
| data_root=None, |
| split_file=None, |
| **kwargs, |
| ): |
| self.lr = np.loadtxt(lr_file, dtype=str) if lr_file is not None else None |
| self.la = torch.load(la_file) if la_file is not None else None |
| self.split_file = split_file |
| self.split = split |
| |
| print(f"[DEBUG ScanNetDataset __init__] data_root received: {data_root}") |
| |
|
|
| |
| super().__init__(split=split, data_root=data_root, **kwargs) |
| |
|
|
| |
| print(f"[DEBUG ScanNetDataset __init__] data_root after super(): {self.data_root}") |
| |
|
|
| def get_data_list(self): |
| |
| if self.split_file is not None and os.path.exists(self.split_file): |
| with open(self.split_file, 'r') as f: |
| data_list = [ |
| os.path.join(self.data_root, self.split, line.strip()) |
| for line in f.readlines() |
| ] |
| print(f"[INFO ScanNetDataset] Loaded {len(data_list)} scenes from split file: {self.split_file}") |
| print(f"[INFO ScanNetDataset] Sample path: {data_list[0] if data_list else 'N/A'}") |
| return data_list |
| |
|
|
| |
| if self.lr is None: |
| return super().get_data_list() |
| else: |
| return [ |
| os.path.join(self.data_root, "train", name) for name in self.lr |
| ] |
|
|
| def get_data(self, idx): |
| data_name = self.get_data_name(idx) |
| data_path = os.path.join(self.data_root, data_name) |
| data_dict = {} |
|
|
| |
| for asset in self.VALID_ASSETS: |
| asset_path = os.path.join(data_path, f"{asset}.npy") |
| if os.path.exists(asset_path): |
| data_dict[asset] = np.load(asset_path) |
| else: |
| |
| if asset in ["coord", "segment20"]: |
| print(f"❌ Error: {asset}.npy not found in {data_path}, this may cause issues.") |
|
|
| |
| required_keys = ["coord", "segment20"] |
| for key in required_keys: |
| if key not in data_dict: |
| print(f"❌ Error: {key} not found in {data_name}, using dummy data...") |
| if key == "coord": |
| data_dict[key] = np.zeros((1, 3), dtype=np.float32) |
| else: |
| data_dict[key] = np.array([self.ignore_index], dtype=np.int64) |
|
|
| |
| if len(data_dict["coord"]) != len(data_dict["segment20"]): |
| print(f"❌ Error: coord and segment20 length mismatch in {data_name}") |
| print(f" coord: {len(data_dict['coord'])}, segment20: {len(data_dict['segment20'])}") |
| min_len = min(len(data_dict["coord"]), len(data_dict["segment20"])) |
| data_dict["coord"] = data_dict["coord"][:min_len] |
| data_dict["segment20"] = data_dict["segment20"][:min_len] |
| if "color" in data_dict: |
| data_dict["color"] = data_dict["color"][:min_len] |
| if "normal" in data_dict: |
| data_dict["normal"] = data_dict["normal"][:min_len] |
| if "instance" in data_dict: |
| data_dict["instance"] = data_dict["instance"][:min_len] |
|
|
| |
| if len(data_dict["coord"]) == 0: |
| print(f"❌ Error: Empty point cloud in {data_name}, using dummy point...") |
| data_dict["coord"] = np.zeros((1, 3), dtype=np.float32) |
| data_dict["segment20"] = np.array([self.ignore_index], dtype=np.int64) |
| if "color" in data_dict: |
| data_dict["color"] = np.zeros((1, 3), dtype=np.uint8) |
| if "normal" in data_dict: |
| data_dict["normal"] = np.zeros((1, 3), dtype=np.float32) |
| if "instance" in data_dict: |
| data_dict["instance"] = np.array([self.ignore_index], dtype=np.int64) |
| |
| |
| keys_to_check = ["coord", "color", "normal", "segment20", "segment200", "instance"] |
| lengths = [len(data_dict[k]) for k in keys_to_check if k in data_dict] |
| if len(lengths) > 0: |
| min_len = min(lengths) |
| if min_len == 0: |
| print(f"⚠️ Warning: Inconsistent array lengths in {data_name}, truncating...") |
| for k in keys_to_check: |
| if k in data_dict: |
| data_dict[k] = data_dict[k][:min_len] |
| |
| data_dict["name"] = data_name |
| if "segment20" in data_dict: |
| data_dict["segment"] = data_dict["segment20"] |
| return data_dict |
|
|
|
|
| @DATASETS.register_module() |
| class ScanNet200Dataset(ScanNetDataset): |
| VALID_ASSETS = [ |
| "coord", |
| "color", |
| "normal", |
| "segment200", |
| "instance", |
| ] |
| class2id = np.array(VALID_CLASS_IDS_200) |