import os.path as osp
import cv2
import numpy as np
import itertools
import os
import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))
from tqdm import tqdm
from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2

class EDEN_Multi(BaseMultiViewDataset):
    def __init__(self, *args, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        super().__init__(*args, **kwargs)
        self.loaded_data = self._load_data()

    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)

    def _get_views(self, idx, resolution, rng, num_views):
        new_seed = rng.integers(0, 2**32) + idx
        new_rng = np.random.default_rng(new_seed)
        img_names = new_rng.permutation(self.img_names)

        views = []
        i = 0
        while len(views) < num_views:
            # Load RGB image
            scene, img_name = img_names[i]
            try:
                rgb_image = imread_cv2(
                    osp.join(self.ROOT, scene, "rgb", f"{img_name}.png")
                )
                depthmap = np.load(
                    osp.join(self.ROOT, scene, "depth", f"{img_name}.npy")
                )
                depthmap = np.nan_to_num(depthmap, nan=0, posinf=0, neginf=0)

                intrinsics = np.load(
                    osp.join(self.ROOT, scene, "cam", f"{img_name}.npz")
                )["intrinsics"]
                # camera pose is not provided, placeholder
                camera_pose = np.eye(4)
            except:
                i += 1
                continue

            rgb_image, depthmap, intrinsics = self._crop_resize_if_necessary(
                rgb_image, depthmap, intrinsics, resolution, rng=rng, info=img_name
            )

            views.append(
                dict(
                    img=rgb_image,
                    depthmap=depthmap.astype(np.float32),
                    camera_pose=camera_pose.astype(np.float32),
                    camera_intrinsics=intrinsics.astype(np.float32),
                    dataset="EDEN",
                    label=img_name,
                    instance=osp.join(self.ROOT, scene, "rgb", f"{img_name}.png"),
                    is_metric=self.is_metric,
                    is_video=False,
                    quantile=np.array(1.0, dtype=np.float32),
                    img_mask=True,
                    ray_mask=False,
                    camera_only=False,
                    depth_only=False,
                    single_view=True,
                    reset=True,
                )
            )
            i += 1
        return views


import os.path as osp
import cv2
import numpy as np
import itertools
import os
import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))
from tqdm import tqdm
from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2

class EDEN_Multi(BaseMultiViewDataset):
    def __init__(self, *args, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        super().__init__(*args, **kwargs)
        self.loaded_data = self._load_data()

    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)


import cv2
import numpy as np
import itertools
import os
import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))
from tqdm import tqdm
from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2

class EDEN_Multi(BaseMultiViewDataset):
    def __init__(self, *args, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        super().__init__(*args, **kwargs)
        self.loaded_data = self._load_data()

    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)

    def _get_views(self, idx, resolution, rng, num_views):
        new_seed = rng.integers(0, 2**32) + idx
        new_rng = np.random.default_rng(new_seed)
        img_names = new_rng.permutation(self.img_names)

        views = []
        i = 0
        while len(views) < num_views:
            # Load RGB image
            scene, img_name = img_names[i]
            try:
                rgb_image = imread_cv2(
                    osp.join(self.ROOT, scene, "rgb", f"{img_name}.png")


    def __init__(self, *args, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        super().__init__(*args, **kwargs)
        self.loaded_data = self._load_data()

    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)

    def _get_views(self, idx, resolution, rng, num_views):
        new_seed = rng.integers(0, 2**32) + idx
        new_rng = np.random.default_rng(new_seed)
        img_names = new_rng.permutation(self.img_names)

        views = []
        i = 0
        while len(views) < num_views:
            # Load RGB image
            scene, img_name = img_names[i]
            try:
                rgb_image = imread_cv2(
                    osp.join(self.ROOT, scene, "rgb", f"{img_name}.png")
                )
                depthmap = np.load(
                    osp.join(self.ROOT, scene, "depth", f"{img_name}.npy")


        self.is_metric = True
        super().__init__(*args, **kwargs)
        self.loaded_data = self._load_data()

    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)

    def _get_views(self, idx, resolution, rng, num_views):
        new_seed = rng.integers(0, 2**32) + idx
        new_rng = np.random.default_rng(new_seed)
        img_names = new_rng.permutation(self.img_names)

        views = []
        i = 0
        while len(views) < num_views:
            # Load RGB image
            scene, img_name = img_names[i]
            try:
                rgb_image = imread_cv2(
                    osp.join(self.ROOT, scene, "rgb", f"{img_name}.png")
                )
                depthmap = np.load(
                    osp.join(self.ROOT, scene, "depth", f"{img_name}.npy")
                )
                depthmap = np.nan_to_num(depthmap, nan=0, posinf=0, neginf=0)


    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)

    def _get_views(self, idx, resolution, rng, num_views):
        new_seed = rng.integers(0, 2**32) + idx
        new_rng = np.random.default_rng(new_seed)
        img_names = new_rng.permutation(self.img_names)

        views = []
        i = 0
        while len(views) < num_views:
            # Load RGB image
            scene, img_name = img_names[i]
            try:
                rgb_image = imread_cv2(
                    osp.join(self.ROOT, scene, "rgb", f"{img_name}.png")
                )
                depthmap = np.load(
                    osp.join(self.ROOT, scene, "depth", f"{img_name}.npy")
                )
                depthmap = np.nan_to_num(depthmap, nan=0, posinf=0, neginf=0)

                intrinsics = np.load(
                    osp.join(self.ROOT, scene, "cam", f"{img_name}.npz")
                )["intrinsics"]
                # camera pose is not provided, placeholder
                camera_pose = np.eye(4)
            except:
                i += 1
                continue

            rgb_image, depthmap, intrinsics = self._crop_resize_if_necessary(
                rgb_image, depthmap, intrinsics, resolution, rng=rng, info=img_name
            )

            views.append(
                dict(
                    img=rgb_image,
                    depthmap=depthmap.astype(np.float32),
                    camera_pose=camera_pose.astype(np.float32),
                    camera_intrinsics=intrinsics.astype(np.float32),
                    dataset="EDEN",
                    label=img_name,
                    instance=osp.join(self.ROOT, scene, "rgb", f"{img_name}.png"),
                    is_metric=self.is_metric,
                    is_video=False,
                    quantile=np.array(1.0, dtype=np.float32),
                    img_mask=True,
                    ray_mask=False,
                    camera_only=False,
                    depth_only=False,
                    single_view=True,
                    reset=True,
                )
            )
            i += 1
        return views


import os.path as osp
import os
import sys
import itertools

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))
import cv2
import numpy as np

from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2

def stratified_sampling(indices, num_samples, rng=None):
    if num_samples > len(indices):
        raise ValueError("num_samples cannot exceed the number of available indices.")
    elif num_samples == len(indices):
        return indices

    sorted_indices = sorted(indices)
    stride = len(sorted_indices) / num_samples
    sampled_indices = []
    if rng is None:
        rng = np.random.default_rng()

    for i in range(num_samples):
        start = int(i * stride)
        end = int((i + 1) * stride)
        # Ensure end does not exceed the list
        end = min(end, len(sorted_indices))
        if start < end:
            # Randomly select within the current stratum
            rand_idx = rng.integers(start, end)
            sampled_indices.append(sorted_indices[rand_idx])
        else:
            # In case of any rounding issues, select the last index
            sampled_indices.append(sorted_indices[-1])

    return rng.permutation(sampled_indices)

class ARKitScenes_Multi(BaseMultiViewDataset):
    def __init__(self, *args, split, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        self.max_interval = 8
        super().__init__(*args, **kwargs)
        if split == "train":
            self.split = "Training"
        elif split == "test":
            self.split = "Test"
        else:
            raise ValueError("")

        self.loaded_data = self._load_data(self.split)

    def _load_data(self, split):
        with np.load(osp.join(self.ROOT, split, "all_metadata.npz")) as data:
            self.scenes: np.ndarray = data["scenes"]
           # check if highres data exists
            highres_path = os.path.join(
                self.ROOT.rstrip("/") + "_highres",
                split if split == "Training" else "Validation"
            )

            if os.path.exists(highres_path):
                # if highres data exists, use the highres data (cut3r logic)
                high_res_list = np.array(
                    [
                        d
                        for d in os.listdir(highres_path)
                        if os.path.join(self.ROOT + "_highres", split, d)
                    ]
                )
                self.scenes = np.setdiff1d(self.scenes, high_res_list)
            # if highres data does not exist, use the normal data list

        offset = 0
        counts = []
        scenes = []
        sceneids = []
        images = []
        intrinsics = []
        trajectories = []
        groups = []
        id_ranges = []
        j = 0
        for scene_idx, scene in enumerate(self.scenes):
            scene_dir = osp.join(self.ROOT, self.split, scene)
            with np.load(
                osp.join(scene_dir, "new_scene_metadata.npz"), allow_pickle=True
            ) as data:
                imgs = data["images"]
                intrins = data["intrinsics"]
                traj = data["trajectories"]
                min_seq_len = (
                    self.num_views
                    if not self.allow_repeat
                    else max(self.num_views // 3, 3)
                )
                if len(imgs) < min_seq_len:
                    print(f"Skipping {scene}")
                    continue

                collections = {}
                assert "image_collection" in data, "Image collection not found"
                collections["image"] = data["image_collection"]

                num_imgs = imgs.shape[0]
                img_groups = []
                min_group_len = (
                    self.num_views
                    if not self.allow_repeat
                    else max(self.num_views // 3, 3)
                )
                for ref_id, group in collections["image"].item().items():
                    if len(group) + 1 < min_group_len:
                        continue

                    # groups are (idx, score)s
                    group.insert(0, (ref_id, 1.0))
                    group = [int(x[0] + offset) for x in group]
                    img_groups.append(sorted(group))

                if len(img_groups) == 0:
                    print(f"Skipping {scene}")
                    continue

                scenes.append(scene)
                sceneids.extend([j] * num_imgs)
                id_ranges.extend([(offset, offset + num_imgs) for _ in range(num_imgs)])
                images.extend(imgs)
                K = np.expand_dims(np.eye(3), 0).repeat(num_imgs, 0)

                K[:, 0, 0] = [fx for _, _, fx, _, _, _ in intrins]
                K[:, 1, 1] = [fy for _, _, _, fy, _, _ in intrins]
                K[:, 0, 2] = [cx for _, _, _, _, cx, _ in intrins]
                K[:, 1, 2] = [cy for _, _, _, _, _, cy in intrins]
                intrinsics.extend(list(K))
                trajectories.extend(list(traj))

                # offset groups
                groups.extend(img_groups)
                counts.append(offset)
                offset += num_imgs
                j += 1

        self.scenes = scenes
        self.sceneids = sceneids
        self.id_ranges = id_ranges
        self.images = images
        self.intrinsics = intrinsics
        self.trajectories = trajectories
        self.groups = groups

    def __len__(self):
        return len(self.groups)

    def get_image_num(self):
        return len(self.images)

    def _get_views(self, idx, resolution, rng, num_views):

        if rng.choice([True, False]):
            image_idxs = np.arange(self.id_ranges[idx][0], self.id_ranges[idx][1])
            cut_off = num_views if not self.allow_repeat else max(num_views // 3, 3)
            start_image_idxs = image_idxs[: len(image_idxs) - cut_off + 1]
            start_id = rng.choice(start_image_idxs)
            pos, ordered_video = self.get_seq_from_start_id(
                num_views,
                start_id,
                image_idxs.tolist(),
                rng,
                max_interval=self.max_interval,
                video_prob=0.8,
                fix_interval_prob=0.5,
                block_shuffle=16,
            )
            image_idxs = np.array(image_idxs)[pos]
        else:
            ordered_video = False
            image_idxs = self.groups[idx]
            image_idxs = rng.permutation(image_idxs)
            if len(image_idxs) > num_views:
                image_idxs = image_idxs[:num_views]
            else:
                if rng.random() < 0.8:
                    image_idxs = rng.choice(image_idxs, size=num_views, replace=True)
                else:
                    repeat_num = num_views // len(image_idxs) + 1
                    image_idxs = np.tile(image_idxs, repeat_num)[:num_views]

        views = []
        for v, view_idx in enumerate(image_idxs):
            scene_id = self.sceneids[view_idx]
            scene_dir = osp.join(self.ROOT, self.split, self.scenes[scene_id])

            intrinsics = self.intrinsics[view_idx]
            camera_pose = self.trajectories[view_idx]
            basename = self.images[view_idx]
            assert (
                basename[:8] == self.scenes[scene_id]
            ), f"{basename}, {self.scenes[scene_id]}"
            # print(scene_dir, basename)
            # Load RGB image
            rgb_image = imread_cv2(
                osp.join(scene_dir, "vga_wide", basename.replace(".png", ".jpg"))
            )
            # Load depthmap
            depthmap = imread_cv2(
                osp.join(scene_dir, "lowres_depth", basename), cv2.IMREAD_UNCHANGED
            )
            depthmap = depthmap.astype(np.float32) / 1000.0
            depthmap[~np.isfinite(depthmap)] = 0  # invalid

            rgb_image, depthmap, intrinsics = self._crop_resize_if_necessary(
                rgb_image, depthmap, intrinsics, resolution, rng=rng, info=view_idx
            )

            # generate img mask and raymap mask
            img_mask, ray_mask = self.get_img_and_ray_masks(
                self.is_metric, v, rng, p=[0.75, 0.2, 0.05]
            )

            views.append(
                dict(
                    img=rgb_image,
                    depthmap=depthmap.astype(np.float32),
                    camera_pose=camera_pose.astype(np.float32),
                    camera_intrinsics=intrinsics.astype(np.float32),
                    dataset="arkitscenes",
                    label=self.scenes[scene_id] + "_" + basename,
                    instance=f"{str(idx)}_{str(view_idx)}",
                    is_metric=self.is_metric,
                    is_video=ordered_video,
                    quantile=np.array(0.98, dtype=np.float32),
                    img_mask=img_mask,
                    ray_mask=ray_mask,
                    camera_only=False,
                    depth_only=False,
                    single_view=False,
                    reset=False,
                )
            )
        assert len(views) == num_views
        return views


import os.path as osp
import os
import sys
import itertools

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))
import cv2
import numpy as np

from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2

def stratified_sampling(indices, num_samples, rng=None):
    if num_samples > len(indices):
        raise ValueError("num_samples cannot exceed the number of available indices.")
    elif num_samples == len(indices):
        return indices

    sorted_indices = sorted(indices)
    stride = len(sorted_indices) / num_samples
    sampled_indices = []
    if rng is None:
        rng = np.random.default_rng()

    for i in range(num_samples):
        start = int(i * stride)
        end = int((i + 1) * stride)
        # Ensure end does not exceed the list
        end = min(end, len(sorted_indices))
        if start < end:
            # Randomly select within the current stratum
            rand_idx = rng.integers(start, end)
            sampled_indices.append(sorted_indices[rand_idx])
        else:
            # In case of any rounding issues, select the last index
            sampled_indices.append(sorted_indices[-1])

    return rng.permutation(sampled_indices)

class ARKitScenes_Multi(BaseMultiViewDataset):
    def __init__(self, *args, split, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        self.max_interval = 8
        super().__init__(*args, **kwargs)
        if split == "train":
            self.split = "Training"
        elif split == "test":
            self.split = "Test"
        else:
            raise ValueError("")

        self.loaded_data = self._load_data(self.split)

    def _load_data(self, split):
        with np.load(osp.join(self.ROOT, split, "all_metadata.npz")) as data:


    sampled_indices = []
    if rng is None:
        rng = np.random.default_rng()

    for i in range(num_samples):
        start = int(i * stride)
        end = int((i + 1) * stride)
        # Ensure end does not exceed the list
        end = min(end, len(sorted_indices))
        if start < end:
            # Randomly select within the current stratum
            rand_idx = rng.integers(start, end)
            sampled_indices.append(sorted_indices[rand_idx])
        else:
            # In case of any rounding issues, select the last index
            sampled_indices.append(sorted_indices[-1])

    return rng.permutation(sampled_indices)

class ARKitScenes_Multi(BaseMultiViewDataset):
    def __init__(self, *args, split, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        self.max_interval = 8
        super().__init__(*args, **kwargs)
        if split == "train":
            self.split = "Training"
        elif split == "test":
            self.split = "Test"
        else:
            raise ValueError("")

        self.loaded_data = self._load_data(self.split)

    def _load_data(self, split):
        with np.load(osp.join(self.ROOT, split, "all_metadata.npz")) as data:
            self.scenes: np.ndarray = data["scenes"]
           # check if highres data exists
            highres_path = os.path.join(
                self.ROOT.rstrip("/") + "_highres",
                split if split == "Training" else "Validation"
            )

            if os.path.exists(highres_path):
                # if highres data exists, use the highres data (cut3r logic)
                high_res_list = np.array(
                    [
                        d
                        for d in os.listdir(highres_path)
                        if os.path.join(self.ROOT + "_highres", split, d)
                    ]
                )
                self.scenes = np.setdiff1d(self.scenes, high_res_list)
            # if highres data does not exist, use the normal data list

        offset = 0
        counts = []
        scenes = []
        sceneids = []
        images = []
        intrinsics = []
        trajectories = []
        groups = []
        id_ranges = []
        j = 0
        for scene_idx, scene in enumerate(self.scenes):
            scene_dir = osp.join(self.ROOT, self.split, scene)
            with np.load(
                osp.join(scene_dir, "new_scene_metadata.npz"), allow_pickle=True
            ) as data:
                imgs = data["images"]
                intrins = data["intrinsics"]
                traj = data["trajectories"]
                min_seq_len = (
                    self.num_views
                    if not self.allow_repeat
                    else max(self.num_views // 3, 3)
                )
                if len(imgs) < min_seq_len:
                    print(f"Skipping {scene}")
                    continue

                collections = {}
                assert "image_collection" in data, "Image collection not found"
                collections["image"] = data["image_collection"]

                num_imgs = imgs.shape[0]
                img_groups = []
                min_group_len = (
                    self.num_views
                    if not self.allow_repeat
                    else max(self.num_views // 3, 3)
                )
                for ref_id, group in collections["image"].item().items():
                    if len(group) + 1 < min_group_len:
                        continue

                    # groups are (idx, score)s
                    group.insert(0, (ref_id, 1.0))
                    group = [int(x[0] + offset) for x in group]
                    img_groups.append(sorted(group))

                if len(img_groups) == 0:
                    print(f"Skipping {scene}")
                    continue

                scenes.append(scene)
                sceneids.extend([j] * num_imgs)
                id_ranges.extend([(offset, offset + num_imgs) for _ in range(num_imgs)])
                images.extend(imgs)
                K = np.expand_dims(np.eye(3), 0).repeat(num_imgs, 0)

                K[:, 0, 0] = [fx for _, _, fx, _, _, _ in intrins]
                K[:, 1, 1] = [fy for _, _, _, fy, _, _ in intrins]
                K[:, 0, 2] = [cx for _, _, _, _, cx, _ in intrins]
                K[:, 1, 2] = [cy for _, _, _, _, _, cy in intrins]
                intrinsics.extend(list(K))
                trajectories.extend(list(traj))

                # offset groups
                groups.extend(img_groups)
                counts.append(offset)
                offset += num_imgs
                j += 1

        self.scenes = scenes
        self.sceneids = sceneids
        self.id_ranges = id_ranges
        self.images = images
        self.intrinsics = intrinsics
        self.trajectories = trajectories
        self.groups = groups

    def __len__(self):
        return len(self.groups)

    def get_image_num(self):
        return len(self.images)

    def _get_views(self, idx, resolution, rng, num_views):

        if rng.choice([True, False]):
            image_idxs = np.arange(self.id_ranges[idx][0], self.id_ranges[idx][1])
            cut_off = num_views if not self.allow_repeat else max(num_views // 3, 3)
            start_image_idxs = image_idxs[: len(image_idxs) - cut_off + 1]
            start_id = rng.choice(start_image_idxs)
            pos, ordered_video = self.get_seq_from_start_id(
                num_views,
                start_id,
                image_idxs.tolist(),
                rng,
                max_interval=self.max_interval,
                video_prob=0.8,
                fix_interval_prob=0.5,
                block_shuffle=16,
            )
            image_idxs = np.array(image_idxs)[pos]
        else:
            ordered_video = False
            image_idxs = self.groups[idx]
            image_idxs = rng.permutation(image_idxs)
            if len(image_idxs) > num_views:
                image_idxs = image_idxs[:num_views]
            else:
                if rng.random() < 0.8:
                    image_idxs = rng.choice(image_idxs, size=num_views, replace=True)
                else:
                    repeat_num = num_views // len(image_idxs) + 1
                    image_idxs = np.tile(image_idxs, repeat_num)[:num_views]

        views = []
        for v, view_idx in enumerate(image_idxs):
            scene_id = self.sceneids[view_idx]
            scene_dir = osp.join(self.ROOT, self.split, self.scenes[scene_id])

            intrinsics = self.intrinsics[view_idx]
            camera_pose = self.trajectories[view_idx]
            basename = self.images[view_idx]
            assert (
                basename[:8] == self.scenes[scene_id]
            ), f"{basename}, {self.scenes[scene_id]}"
            # print(scene_dir, basename)
            # Load RGB image
            rgb_image = imread_cv2(
                osp.join(scene_dir, "vga_wide", basename.replace(".png", ".jpg"))
            )
            # Load depthmap
            depthmap = imread_cv2(
                osp.join(scene_dir, "lowres_depth", basename), cv2.IMREAD_UNCHANGED
            )
            depthmap = depthmap.astype(np.float32) / 1000.0
            depthmap[~np.isfinite(depthmap)] = 0  # invalid

            rgb_image, depthmap, intrinsics = self._crop_resize_if_necessary(
                rgb_image, depthmap, intrinsics, resolution, rng=rng, info=view_idx
            )

            # generate img mask and raymap mask
            img_mask, ray_mask = self.get_img_and_ray_masks(
                self.is_metric, v, rng, p=[0.75, 0.2, 0.05]
            )

            views.append(
                dict(
                    img=rgb_image,
                    depthmap=depthmap.astype(np.float32),
                    camera_pose=camera_pose.astype(np.float32),
                    camera_intrinsics=intrinsics.astype(np.float32),
                    dataset="arkitscenes",
                    label=self.scenes[scene_id] + "_" + basename,
                    instance=f"{str(idx)}_{str(view_idx)}",
                    is_metric=self.is_metric,
                    is_video=ordered_video,
                    quantile=np.array(0.98, dtype=np.float32),
                    img_mask=img_mask,
                    ray_mask=ray_mask,
                    camera_only=False,
                    depth_only=False,
                    single_view=False,
                    reset=False,
                )
            )
        assert len(views) == num_views
        return views


    if rng is None:
        rng = np.random.default_rng()

    for i in range(num_samples):
        start = int(i * stride)
        end = int((i + 1) * stride)
        # Ensure end does not exceed the list
        end = min(end, len(sorted_indices))
        if start < end:
            # Randomly select within the current stratum
            rand_idx = rng.integers(start, end)
            sampled_indices.append(sorted_indices[rand_idx])
        else:
            # In case of any rounding issues, select the last index
            sampled_indices.append(sorted_indices[-1])

    return rng.permutation(sampled_indices)

class ARKitScenes_Multi(BaseMultiViewDataset):
    def __init__(self, *args, split, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        self.max_interval = 8
        super().__init__(*args, **kwargs)
        if split == "train":
            self.split = "Training"
        elif split == "test":
            self.split = "Test"
        else:
            raise ValueError("")

        self.loaded_data = self._load_data(self.split)

    def _load_data(self, split):
        with np.load(osp.join(self.ROOT, split, "all_metadata.npz")) as data:
            self.scenes: np.ndarray = data["scenes"]
           # check if highres data exists
            highres_path = os.path.join(
                self.ROOT.rstrip("/") + "_highres",
                split if split == "Training" else "Validation"
            )

            if os.path.exists(highres_path):
                # if highres data exists, use the highres data (cut3r logic)
                high_res_list = np.array(
                    [
                        d
                        for d in os.listdir(highres_path)
                        if os.path.join(self.ROOT + "_highres", split, d)
                    ]
                )
                self.scenes = np.setdiff1d(self.scenes, high_res_list)


    return rng.permutation(sampled_indices)

class ARKitScenes_Multi(BaseMultiViewDataset):
    def __init__(self, *args, split, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        self.max_interval = 8
        super().__init__(*args, **kwargs)
        if split == "train":
            self.split = "Training"
        elif split == "test":
            self.split = "Test"
        else:
            raise ValueError("")

        self.loaded_data = self._load_data(self.split)

    def _load_data(self, split):
        with np.load(osp.join(self.ROOT, split, "all_metadata.npz")) as data:
            self.scenes: np.ndarray = data["scenes"]
           # check if highres data exists
            highres_path = os.path.join(
                self.ROOT.rstrip("/") + "_highres",
                split if split == "Training" else "Validation"
            )

            if os.path.exists(highres_path):
                # if highres data exists, use the highres data (cut3r logic)
                high_res_list = np.array(
                    [
                        d
                        for d in os.listdir(highres_path)
                        if os.path.join(self.ROOT + "_highres", split, d)
                    ]
                )
                self.scenes = np.setdiff1d(self.scenes, high_res_list)
            # if highres data does not exist, use the normal data list

        offset = 0
        counts = []
        scenes = []
        sceneids = []
        images = []
        intrinsics = []
        trajectories = []
        groups = []
        id_ranges = []
        j = 0
        for scene_idx, scene in enumerate(self.scenes):
            scene_dir = osp.join(self.ROOT, self.split, scene)
            with np.load(
                osp.join(scene_dir, "new_scene_metadata.npz"), allow_pickle=True
            ) as data:
                imgs = data["images"]
                intrins = data["intrinsics"]
                traj = data["trajectories"]
                min_seq_len = (
                    self.num_views
                    if not self.allow_repeat
                    else max(self.num_views // 3, 3)
                )
                if len(imgs) < min_seq_len:
                    print(f"Skipping {scene}")
                    continue

                collections = {}
                assert "image_collection" in data, "Image collection not found"
                collections["image"] = data["image_collection"]

                num_imgs = imgs.shape[0]
                img_groups = []
                min_group_len = (
                    self.num_views
                    if not self.allow_repeat
                    else max(self.num_views // 3, 3)
                )
                for ref_id, group in collections["image"].item().items():
                    if len(group) + 1 < min_group_len:
                        continue

                    # groups are (idx, score)s
                    group.insert(0, (ref_id, 1.0))
                    group = [int(x[0] + offset) for x in group]
                    img_groups.append(sorted(group))

                if len(img_groups) == 0:
                    print(f"Skipping {scene}")
                    continue

                scenes.append(scene)
                sceneids.extend([j] * num_imgs)
                id_ranges.extend([(offset, offset + num_imgs) for _ in range(num_imgs)])
                images.extend(imgs)
                K = np.expand_dims(np.eye(3), 0).repeat(num_imgs, 0)

                K[:, 0, 0] = [fx for _, _, fx, _, _, _ in intrins]
                K[:, 1, 1] = [fy for _, _, _, fy, _, _ in intrins]
                K[:, 0, 2] = [cx for _, _, _, _, cx, _ in intrins]
                K[:, 1, 2] = [cy for _, _, _, _, _, cy in intrins]
                intrinsics.extend(list(K))
                trajectories.extend(list(traj))

                # offset groups
                groups.extend(img_groups)
                counts.append(offset)
                offset += num_imgs
                j += 1

        self.scenes = scenes
        self.sceneids = sceneids
        self.id_ranges = id_ranges
        self.images = images
        self.intrinsics = intrinsics
        self.trajectories = trajectories
        self.groups = groups

    def __len__(self):
        return len(self.groups)

    def get_image_num(self):
        return len(self.images)

    def _get_views(self, idx, resolution, rng, num_views):

        if rng.choice([True, False]):
            image_idxs = np.arange(self.id_ranges[idx][0], self.id_ranges[idx][1])
            cut_off = num_views if not self.allow_repeat else max(num_views // 3, 3)
            start_image_idxs = image_idxs[: len(image_idxs) - cut_off + 1]
            start_id = rng.choice(start_image_idxs)
            pos, ordered_video = self.get_seq_from_start_id(
                num_views,
                start_id,
                image_idxs.tolist(),
                rng,
                max_interval=self.max_interval,


                K[:, 1, 1] = [fy for _, _, _, fy, _, _ in intrins]
                K[:, 0, 2] = [cx for _, _, _, _, cx, _ in intrins]
                K[:, 1, 2] = [cy for _, _, _, _, _, cy in intrins]
                intrinsics.extend(list(K))
                trajectories.extend(list(traj))

                # offset groups
                groups.extend(img_groups)
                counts.append(offset)
                offset += num_imgs
                j += 1

        self.scenes = scenes
        self.sceneids = sceneids
        self.id_ranges = id_ranges
        self.images = images
        self.intrinsics = intrinsics
        self.trajectories = trajectories
        self.groups = groups

    def __len__(self):
        return len(self.groups)

    def get_image_num(self):
        return len(self.images)

    def _get_views(self, idx, resolution, rng, num_views):

        if rng.choice([True, False]):
            image_idxs = np.arange(self.id_ranges[idx][0], self.id_ranges[idx][1])
            cut_off = num_views if not self.allow_repeat else max(num_views // 3, 3)
            start_image_idxs = image_idxs[: len(image_idxs) - cut_off + 1]
            start_id = rng.choice(start_image_idxs)
            pos, ordered_video = self.get_seq_from_start_id(
                num_views,
                start_id,
                image_idxs.tolist(),
                rng,
                max_interval=self.max_interval,
                video_prob=0.8,
                fix_interval_prob=0.5,
                block_shuffle=16,


                intrinsics.extend(list(K))
                trajectories.extend(list(traj))

                # offset groups
                groups.extend(img_groups)
                counts.append(offset)
                offset += num_imgs
                j += 1

        self.scenes = scenes
        self.sceneids = sceneids
        self.id_ranges = id_ranges
        self.images = images
        self.intrinsics = intrinsics
        self.trajectories = trajectories
        self.groups = groups

    def __len__(self):
        return len(self.groups)

    def get_image_num(self):
        return len(self.images)

    def _get_views(self, idx, resolution, rng, num_views):

        if rng.choice([True, False]):
            image_idxs = np.arange(self.id_ranges[idx][0], self.id_ranges[idx][1])
            cut_off = num_views if not self.allow_repeat else max(num_views // 3, 3)
            start_image_idxs = image_idxs[: len(image_idxs) - cut_off + 1]
            start_id = rng.choice(start_image_idxs)
            pos, ordered_video = self.get_seq_from_start_id(
                num_views,
                start_id,
                image_idxs.tolist(),
                rng,
                max_interval=self.max_interval,
                video_prob=0.8,
                fix_interval_prob=0.5,
                block_shuffle=16,
            )
            image_idxs = np.array(image_idxs)[pos]
        else:


                # offset groups
                groups.extend(img_groups)
                counts.append(offset)
                offset += num_imgs
                j += 1

        self.scenes = scenes
        self.sceneids = sceneids
        self.id_ranges = id_ranges
        self.images = images
        self.intrinsics = intrinsics
        self.trajectories = trajectories
        self.groups = groups

    def __len__(self):
        return len(self.groups)

    def get_image_num(self):
        return len(self.images)

    def _get_views(self, idx, resolution, rng, num_views):

        if rng.choice([True, False]):
            image_idxs = np.arange(self.id_ranges[idx][0], self.id_ranges[idx][1])
            cut_off = num_views if not self.allow_repeat else max(num_views // 3, 3)
            start_image_idxs = image_idxs[: len(image_idxs) - cut_off + 1]
            start_id = rng.choice(start_image_idxs)
            pos, ordered_video = self.get_seq_from_start_id(
                num_views,
                start_id,
                image_idxs.tolist(),
                rng,
                max_interval=self.max_interval,
                video_prob=0.8,
                fix_interval_prob=0.5,
                block_shuffle=16,
            )
            image_idxs = np.array(image_idxs)[pos]
        else:
            ordered_video = False
            image_idxs = self.groups[idx]
            image_idxs = rng.permutation(image_idxs)
            if len(image_idxs) > num_views:
                image_idxs = image_idxs[:num_views]
            else:
                if rng.random() < 0.8:
                    image_idxs = rng.choice(image_idxs, size=num_views, replace=True)
                else:
                    repeat_num = num_views // len(image_idxs) + 1
                    image_idxs = np.tile(image_idxs, repeat_num)[:num_views]

        views = []
        for v, view_idx in enumerate(image_idxs):
            scene_id = self.sceneids[view_idx]
            scene_dir = osp.join(self.ROOT, self.split, self.scenes[scene_id])

            intrinsics = self.intrinsics[view_idx]
            camera_pose = self.trajectories[view_idx]
            basename = self.images[view_idx]
            assert (
                basename[:8] == self.scenes[scene_id]
            ), f"{basename}, {self.scenes[scene_id]}"
            # print(scene_dir, basename)
            # Load RGB image
            rgb_image = imread_cv2(
                osp.join(scene_dir, "vga_wide", basename.replace(".png", ".jpg"))
            )
            # Load depthmap
            depthmap = imread_cv2(
                osp.join(scene_dir, "lowres_depth", basename), cv2.IMREAD_UNCHANGED
            )
            depthmap = depthmap.astype(np.float32) / 1000.0
            depthmap[~np.isfinite(depthmap)] = 0  # invalid

            rgb_image, depthmap, intrinsics = self._crop_resize_if_necessary(
                rgb_image, depthmap, intrinsics, resolution, rng=rng, info=view_idx
            )

            # generate img mask and raymap mask
            img_mask, ray_mask = self.get_img_and_ray_masks(
                self.is_metric, v, rng, p=[0.75, 0.2, 0.05]
            )

            views.append(
                dict(
                    img=rgb_image,
                    depthmap=depthmap.astype(np.float32),
                    camera_pose=camera_pose.astype(np.float32),
                    camera_intrinsics=intrinsics.astype(np.float32),
                    dataset="arkitscenes",
                    label=self.scenes[scene_id] + "_" + basename,
                    instance=f"{str(idx)}_{str(view_idx)}",
                    is_metric=self.is_metric,
                    is_video=ordered_video,
                    quantile=np.array(0.98, dtype=np.float32),
                    img_mask=img_mask,
                    ray_mask=ray_mask,
                    camera_only=False,
                    depth_only=False,
                    single_view=False,
                    reset=False,
                )
            )
        assert len(views) == num_views
        return views


import os.path as osp
import cv2
import numpy as np
import itertools
import os
import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))

from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2

class ScanNetpp_Multi(BaseMultiViewDataset):
    def __init__(self, *args, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        self.max_interval = 3
        super().__init__(*args, **kwargs)
        assert self.split == "train"
        self.loaded_data = self._load_data()

    def _load_data(self):
        with np.load(osp.join(self.ROOT, "all_metadata.npz")) as data:
            self.scenes = data["scenes"]
        offset = 0
        scenes = []
        sceneids = []
        images = []
        intrinsics = []
        trajectories = []
        groups = []
        id_ranges = []
        j = 0
        self.image_num = 0
        for scene in self.scenes:
            scene_dir = osp.join(self.ROOT, scene)
            with np.load(
                osp.join(scene_dir, "new_scene_metadata.npz"), allow_pickle=True
            ) as data:
                imgs = data["images"]
                self.image_num += len(imgs)
                img_ids = np.arange(len(imgs)).tolist()
                intrins = data["intrinsics"]
                traj = data["trajectories"]
                imgs_on_disk = sorted(os.listdir(osp.join(scene_dir, "images")))
                imgs_on_disk = list(map(lambda x: x[:-4], imgs_on_disk))

                dslr_ids = [
                    i + offset
                    for i in img_ids
                    if imgs[i].startswith("DSC") and imgs[i] in imgs_on_disk
                ]
                iphone_ids = [
                    i + offset
                    for i in img_ids
                    if imgs[i].startswith("frame") and imgs[i] in imgs_on_disk
                ]

                num_imgs = len(imgs)
                assert max(dslr_ids) < min(iphone_ids)
                assert "image_collection" in data

                img_groups = []
                img_id_ranges = []

                for ref_id, group in data["image_collection"].item().items():
                    if len(group) + 1 < self.num_views:
                        continue
                    group.insert(0, (ref_id, 1.0))
                    sorted_group = sorted(group, key=lambda x: x[1], reverse=True)
                    group = [int(x[0] + offset) for x in sorted_group]
                    img_groups.append(sorted(group))

                    if imgs[ref_id].startswith("frame"):
                        img_id_ranges.append(dslr_ids)
                    else:
                        img_id_ranges.append(iphone_ids)

                if len(img_groups) == 0:
                    print(f"Skipping {scene}")
                    continue
                scenes.append(scene)
                sceneids.extend([j] * num_imgs)
                images.extend(imgs)
                intrinsics.append(intrins)
                trajectories.append(traj)

                # offset groups
                groups.extend(img_groups)
                id_ranges.extend(img_id_ranges)
                offset += num_imgs
                j += 1

        self.scenes = scenes
        self.sceneids = sceneids
        self.images = images
        self.intrinsics = np.concatenate(intrinsics, axis=0)
        self.trajectories = np.concatenate(trajectories, axis=0)
        self.id_ranges = id_ranges
        self.groups = groups

    def __len__(self):
        return len(self.groups) * 10

    def get_image_num(self):
        return self.image_num

    def _get_views(self, idx, resolution, rng, num_views):
        idx = idx // 10
        image_idxs = self.groups[idx]
        rand_val = rng.random()

        image_idxs_video = self.id_ranges[idx]
        cut_off = num_views if not self.allow_repeat else max(num_views // 3, 3)
        start_image_idxs = image_idxs_video[: len(image_idxs_video) - cut_off + 1]

        if rand_val < 0.7 and len(start_image_idxs) > 0:
            start_id = rng.choice(start_image_idxs)
            pos, ordered_video = self.get_seq_from_start_id(
                num_views,
                start_id,
                image_idxs_video,
                rng,
                max_interval=self.max_interval,
                video_prob=0.8,
                fix_interval_prob=0.5,
                block_shuffle=16,
            )
            image_idxs = np.array(image_idxs_video)[pos]

        else:
            ordered_video = True
            # ordered video with varying intervals
            num_candidates = len(image_idxs)
            max_id = min(num_candidates, int(num_views * (2 + 2 * rng.random())))
            image_idxs = sorted(rng.permutation(image_idxs[:max_id])[:num_views])
            if rand_val > 0.75:
                ordered_video = False
                image_idxs = rng.permutation(image_idxs)

        views = []
        for v, view_idx in enumerate(image_idxs):
            scene_id = self.sceneids[view_idx]
            scene_dir = osp.join(self.ROOT, self.scenes[scene_id])

            intrinsics = self.intrinsics[view_idx]
            camera_pose = self.trajectories[view_idx]
            basename = self.images[view_idx]

            # Load RGB image
            rgb_image = imread_cv2(osp.join(scene_dir, "images", basename + ".jpg"))
            # Load depthmap
            depthmap = imread_cv2(
                osp.join(scene_dir, "depth", basename + ".png"), cv2.IMREAD_UNCHANGED
            )
            depthmap = depthmap.astype(np.float32) / 1000
            depthmap[~np.isfinite(depthmap)] = 0  # invalid

            rgb_image, depthmap, intrinsics = self._crop_resize_if_necessary(
                rgb_image, depthmap, intrinsics, resolution, rng=rng, info=view_idx
            )

            # generate img mask and raymap mask
            img_mask, ray_mask = self.get_img_and_ray_masks(
                self.is_metric, v, rng, p=[0.75, 0.2, 0.05]
            )

            views.append(
                dict(
                    img=rgb_image,
                    depthmap=depthmap.astype(np.float32),
                    camera_pose=camera_pose.astype(np.float32),
                    camera_intrinsics=intrinsics.astype(np.float32),
                    dataset="ScanNet++",
                    label=self.scenes[scene_id] + "_" + basename,
                    instance=f"{str(idx)}_{str(view_idx)}",
                    is_metric=self.is_metric,
                    is_video=ordered_video,
                    quantile=np.array(0.99, dtype=np.float32),
                    img_mask=img_mask,
                    ray_mask=ray_mask,
                    camera_only=False,
                    depth_only=False,
                    single_view=False,
                    reset=False,
                )
            )
        assert len(views) == num_views
        return views


import os.path as osp
import cv2
import numpy as np
import itertools
import os
import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))

from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2

class ScanNetpp_Multi(BaseMultiViewDataset):
    def __init__(self, *args, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        self.max_interval = 3
        super().__init__(*args, **kwargs)
        assert self.split == "train"
        self.loaded_data = self._load_data()

    def _load_data(self):
        with np.load(osp.join(self.ROOT, "all_metadata.npz")) as data:
            self.scenes = data["scenes"]
        offset = 0
        scenes = []
        sceneids = []
        images = []
        intrinsics = []
        trajectories = []
        groups = []
        id_ranges = []
        j = 0
        self.image_num = 0
        for scene in self.scenes:
            scene_dir = osp.join(self.ROOT, scene)
            with np.load(
                osp.join(scene_dir, "new_scene_metadata.npz"), allow_pickle=True
            ) as data:
                imgs = data["images"]


import itertools
import os
import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))

from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2

class ScanNetpp_Multi(BaseMultiViewDataset):
    def __init__(self, *args, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = True
        self.is_metric = True
        self.max_interval = 3
        super().__init__(*args, **kwargs)
        assert self.split == "train"
        self.loaded_data = self._load_data()

    def _load_data(self):
        with np.load(osp.join(self.ROOT, "all_metadata.npz")) as data:
            self.scenes = data["scenes"]
        offset = 0
        scenes = []
        sceneids = []
        images = []
        intrinsics = []
        trajectories = []
        groups = []
        id_ranges = []
        j = 0
        self.image_num = 0
        for scene in self.scenes:
            scene_dir = osp.join(self.ROOT, scene)
            with np.load(
                osp.join(scene_dir, "new_scene_metadata.npz"), allow_pickle=True
            ) as data:
                imgs = data["images"]
                self.image_num += len(imgs)
                img_ids = np.arange(len(imgs)).tolist()
                intrins = data["intrinsics"]
                traj = data["trajectories"]
                imgs_on_disk = sorted(os.listdir(osp.join(scene_dir, "images")))
                imgs_on_disk = list(map(lambda x: x[:-4], imgs_on_disk))

                dslr_ids = [
                    i + offset
                    for i in img_ids
                    if imgs[i].startswith("DSC") and imgs[i] in imgs_on_disk
                ]
                iphone_ids = [
                    i + offset
                    for i in img_ids
                    if imgs[i].startswith("frame") and imgs[i] in imgs_on_disk
                ]

                num_imgs = len(imgs)
                assert max(dslr_ids) < min(iphone_ids)
                assert "image_collection" in data

                img_groups = []
                img_id_ranges = []

                for ref_id, group in data["image_collection"].item().items():
                    if len(group) + 1 < self.num_views:
                        continue
                    group.insert(0, (ref_id, 1.0))
                    sorted_group = sorted(group, key=lambda x: x[1], reverse=True)
                    group = [int(x[0] + offset) for x in sorted_group]
                    img_groups.append(sorted(group))

                    if imgs[ref_id].startswith("frame"):
                        img_id_ranges.append(dslr_ids)
                    else:
                        img_id_ranges.append(iphone_ids)

                if len(img_groups) == 0:
                    print(f"Skipping {scene}")
                    continue
                scenes.append(scene)
                sceneids.extend([j] * num_imgs)
                images.extend(imgs)
                intrinsics.append(intrins)
                trajectories.append(traj)

                # offset groups
                groups.extend(img_groups)
                id_ranges.extend(img_id_ranges)
                offset += num_imgs
                j += 1

        self.scenes = scenes
        self.sceneids = sceneids
        self.images = images
        self.intrinsics = np.concatenate(intrinsics, axis=0)
        self.trajectories = np.concatenate(trajectories, axis=0)
        self.id_ranges = id_ranges
        self.groups = groups

    def __len__(self):
        return len(self.groups) * 10

    def get_image_num(self):
        return self.image_num

    def _get_views(self, idx, resolution, rng, num_views):
        idx = idx // 10
        image_idxs = self.groups[idx]
        rand_val = rng.random()

        image_idxs_video = self.id_ranges[idx]
        cut_off = num_views if not self.allow_repeat else max(num_views // 3, 3)
        start_image_idxs = image_idxs_video[: len(image_idxs_video) - cut_off + 1]

        if rand_val < 0.7 and len(start_image_idxs) > 0:
            start_id = rng.choice(start_image_idxs)
            pos, ordered_video = self.get_seq_from_start_id(
                num_views,


                scenes.append(scene)
                sceneids.extend([j] * num_imgs)
                images.extend(imgs)
                intrinsics.append(intrins)
                trajectories.append(traj)

                # offset groups
                groups.extend(img_groups)
                id_ranges.extend(img_id_ranges)
                offset += num_imgs
                j += 1

        self.scenes = scenes
        self.sceneids = sceneids
        self.images = images
        self.intrinsics = np.concatenate(intrinsics, axis=0)
        self.trajectories = np.concatenate(trajectories, axis=0)
        self.id_ranges = id_ranges
        self.groups = groups

    def __len__(self):
        return len(self.groups) * 10

    def get_image_num(self):
        return self.image_num

    def _get_views(self, idx, resolution, rng, num_views):
        idx = idx // 10
        image_idxs = self.groups[idx]
        rand_val = rng.random()

        image_idxs_video = self.id_ranges[idx]
        cut_off = num_views if not self.allow_repeat else max(num_views // 3, 3)
        start_image_idxs = image_idxs_video[: len(image_idxs_video) - cut_off + 1]

        if rand_val < 0.7 and len(start_image_idxs) > 0:
            start_id = rng.choice(start_image_idxs)
            pos, ordered_video = self.get_seq_from_start_id(
                num_views,
                start_id,
                image_idxs_video,
                rng,


                intrinsics.append(intrins)
                trajectories.append(traj)

                # offset groups
                groups.extend(img_groups)
                id_ranges.extend(img_id_ranges)
                offset += num_imgs
                j += 1

        self.scenes = scenes
        self.sceneids = sceneids
        self.images = images
        self.intrinsics = np.concatenate(intrinsics, axis=0)
        self.trajectories = np.concatenate(trajectories, axis=0)
        self.id_ranges = id_ranges
        self.groups = groups

    def __len__(self):
        return len(self.groups) * 10

    def get_image_num(self):
        return self.image_num

    def _get_views(self, idx, resolution, rng, num_views):
        idx = idx // 10
        image_idxs = self.groups[idx]
        rand_val = rng.random()

        image_idxs_video = self.id_ranges[idx]
        cut_off = num_views if not self.allow_repeat else max(num_views // 3, 3)
        start_image_idxs = image_idxs_video[: len(image_idxs_video) - cut_off + 1]

        if rand_val < 0.7 and len(start_image_idxs) > 0:
            start_id = rng.choice(start_image_idxs)
            pos, ordered_video = self.get_seq_from_start_id(
                num_views,
                start_id,
                image_idxs_video,
                rng,
                max_interval=self.max_interval,
                video_prob=0.8,
                fix_interval_prob=0.5,


                # offset groups
                groups.extend(img_groups)
                id_ranges.extend(img_id_ranges)
                offset += num_imgs
                j += 1

        self.scenes = scenes
        self.sceneids = sceneids
        self.images = images
        self.intrinsics = np.concatenate(intrinsics, axis=0)
        self.trajectories = np.concatenate(trajectories, axis=0)
        self.id_ranges = id_ranges
        self.groups = groups

    def __len__(self):
        return len(self.groups) * 10

    def get_image_num(self):
        return self.image_num

    def _get_views(self, idx, resolution, rng, num_views):
        idx = idx // 10
        image_idxs = self.groups[idx]
        rand_val = rng.random()

        image_idxs_video = self.id_ranges[idx]
        cut_off = num_views if not self.allow_repeat else max(num_views // 3, 3)
        start_image_idxs = image_idxs_video[: len(image_idxs_video) - cut_off + 1]

        if rand_val < 0.7 and len(start_image_idxs) > 0:
            start_id = rng.choice(start_image_idxs)
            pos, ordered_video = self.get_seq_from_start_id(
                num_views,
                start_id,
                image_idxs_video,
                rng,
                max_interval=self.max_interval,
                video_prob=0.8,
                fix_interval_prob=0.5,
                block_shuffle=16,
            )
            image_idxs = np.array(image_idxs_video)[pos]

        else:
            ordered_video = True
            # ordered video with varying intervals
            num_candidates = len(image_idxs)
            max_id = min(num_candidates, int(num_views * (2 + 2 * rng.random())))
            image_idxs = sorted(rng.permutation(image_idxs[:max_id])[:num_views])
            if rand_val > 0.75:
                ordered_video = False
                image_idxs = rng.permutation(image_idxs)

        views = []
        for v, view_idx in enumerate(image_idxs):
            scene_id = self.sceneids[view_idx]
            scene_dir = osp.join(self.ROOT, self.scenes[scene_id])

            intrinsics = self.intrinsics[view_idx]
            camera_pose = self.trajectories[view_idx]
            basename = self.images[view_idx]

            # Load RGB image
            rgb_image = imread_cv2(osp.join(scene_dir, "images", basename + ".jpg"))
            # Load depthmap
            depthmap = imread_cv2(
                osp.join(scene_dir, "depth", basename + ".png"), cv2.IMREAD_UNCHANGED
            )
            depthmap = depthmap.astype(np.float32) / 1000
            depthmap[~np.isfinite(depthmap)] = 0  # invalid

            rgb_image, depthmap, intrinsics = self._crop_resize_if_necessary(
                rgb_image, depthmap, intrinsics, resolution, rng=rng, info=view_idx
            )

            # generate img mask and raymap mask
            img_mask, ray_mask = self.get_img_and_ray_masks(
                self.is_metric, v, rng, p=[0.75, 0.2, 0.05]
            )

            views.append(
                dict(
                    img=rgb_image,
                    depthmap=depthmap.astype(np.float32),
                    camera_pose=camera_pose.astype(np.float32),
                    camera_intrinsics=intrinsics.astype(np.float32),
                    dataset="ScanNet++",
                    label=self.scenes[scene_id] + "_" + basename,
                    instance=f"{str(idx)}_{str(view_idx)}",
                    is_metric=self.is_metric,
                    is_video=ordered_video,
                    quantile=np.array(0.99, dtype=np.float32),
                    img_mask=img_mask,
                    ray_mask=ray_mask,
                    camera_only=False,
                    depth_only=False,
                    single_view=False,
                    reset=False,
                )
            )
        assert len(views) == num_views
        return views


import os.path as osp
import cv2
import numpy as np
import itertools
import os
import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))
from tqdm import tqdm
from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2

class IRS(BaseMultiViewDataset):
    def __init__(self, *args, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = False
        self.is_metric = True
        super().__init__(*args, **kwargs)
        self.loaded_data = self._load_data()

    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)

    def _get_views(self, idx, resolution, rng, num_views):
        new_seed = rng.integers(0, 2**32) + idx
        new_rng = np.random.default_rng(new_seed)
        img_names = new_rng.choice(self.img_names, num_views, replace=False)

        views = []
        for v, img_name in enumerate(img_names):
            # Load RGB image
            scene, img_name = img_name
            rgb_image = imread_cv2(osp.join(self.ROOT, scene, "rgb", f"{img_name}.png"))
            depthmap = np.load(osp.join(self.ROOT, scene, "depth", f"{img_name}.npy"))
            depthmap[depthmap > 200] = 0.0
            depthmap = np.nan_to_num(depthmap, nan=0, posinf=0, neginf=0)

            intrinsics = np.load(osp.join(self.ROOT, scene, "cam", f"{img_name}.npz"))[
                "intrinsics"
            ]
            # camera pose is not provided, placeholder
            camera_pose = np.eye(4)

            rgb_image, depthmap, intrinsics = self._crop_resize_if_necessary(
                rgb_image, depthmap, intrinsics, resolution, rng=rng, info=img_name
            )

            views.append(
                dict(
                    img=rgb_image,
                    depthmap=depthmap.astype(np.float32),
                    camera_pose=camera_pose.astype(np.float32),
                    camera_intrinsics=intrinsics.astype(np.float32),
                    dataset="irs",
                    label=img_name,
                    instance=f"{str(idx)}_{img_name}",
                    is_metric=self.is_metric,
                    is_video=False,
                    quantile=np.array(1.0, dtype=np.float32),
                    img_mask=True,
                    ray_mask=False,
                    camera_only=False,
                    depth_only=False,
                    single_view=True,
                    reset=True,
                )
            )
        assert len(views) == num_views
        return views


import os.path as osp
import cv2
import numpy as np
import itertools
import os
import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))
from tqdm import tqdm
from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2

class IRS(BaseMultiViewDataset):
    def __init__(self, *args, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = False
        self.is_metric = True
        super().__init__(*args, **kwargs)
        self.loaded_data = self._load_data()

    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)


import cv2
import numpy as np
import itertools
import os
import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))
from tqdm import tqdm
from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2

class IRS(BaseMultiViewDataset):
    def __init__(self, *args, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = False
        self.is_metric = True
        super().__init__(*args, **kwargs)
        self.loaded_data = self._load_data()

    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)

    def _get_views(self, idx, resolution, rng, num_views):
        new_seed = rng.integers(0, 2**32) + idx
        new_rng = np.random.default_rng(new_seed)
        img_names = new_rng.choice(self.img_names, num_views, replace=False)

        views = []
        for v, img_name in enumerate(img_names):
            # Load RGB image
            scene, img_name = img_name
            rgb_image = imread_cv2(osp.join(self.ROOT, scene, "rgb", f"{img_name}.png"))
            depthmap = np.load(osp.join(self.ROOT, scene, "depth", f"{img_name}.npy"))
            depthmap[depthmap > 200] = 0.0
            depthmap = np.nan_to_num(depthmap, nan=0, posinf=0, neginf=0)


    def __init__(self, *args, ROOT, **kwargs):
        self.ROOT = ROOT
        self.video = False
        self.is_metric = True
        super().__init__(*args, **kwargs)
        self.loaded_data = self._load_data()

    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)

    def _get_views(self, idx, resolution, rng, num_views):
        new_seed = rng.integers(0, 2**32) + idx
        new_rng = np.random.default_rng(new_seed)
        img_names = new_rng.choice(self.img_names, num_views, replace=False)

        views = []
        for v, img_name in enumerate(img_names):
            # Load RGB image
            scene, img_name = img_name
            rgb_image = imread_cv2(osp.join(self.ROOT, scene, "rgb", f"{img_name}.png"))
            depthmap = np.load(osp.join(self.ROOT, scene, "depth", f"{img_name}.npy"))
            depthmap[depthmap > 200] = 0.0
            depthmap = np.nan_to_num(depthmap, nan=0, posinf=0, neginf=0)

            intrinsics = np.load(osp.join(self.ROOT, scene, "cam", f"{img_name}.npz"))[
                "intrinsics"


        self.is_metric = True
        super().__init__(*args, **kwargs)
        self.loaded_data = self._load_data()

    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)

    def _get_views(self, idx, resolution, rng, num_views):
        new_seed = rng.integers(0, 2**32) + idx
        new_rng = np.random.default_rng(new_seed)
        img_names = new_rng.choice(self.img_names, num_views, replace=False)

        views = []
        for v, img_name in enumerate(img_names):
            # Load RGB image
            scene, img_name = img_name
            rgb_image = imread_cv2(osp.join(self.ROOT, scene, "rgb", f"{img_name}.png"))
            depthmap = np.load(osp.join(self.ROOT, scene, "depth", f"{img_name}.npy"))
            depthmap[depthmap > 200] = 0.0
            depthmap = np.nan_to_num(depthmap, nan=0, posinf=0, neginf=0)

            intrinsics = np.load(osp.join(self.ROOT, scene, "cam", f"{img_name}.npz"))[
                "intrinsics"
            ]
            # camera pose is not provided, placeholder
            camera_pose = np.eye(4)


    def _load_data(self):
        scenes = os.listdir(self.ROOT)
        img_names = []
        for scene in scenes:
            scene_dir = osp.join(self.ROOT, scene)
            rgb_dir = osp.join(scene_dir, "rgb")
            basenames = sorted(
                [f[:-4] for f in os.listdir(rgb_dir) if f.endswith(".png")]
            )
            img_names.extend([(scene, basename) for basename in basenames])

        self.img_names = img_names

    def __len__(self):
        return len(self.img_names)

    def get_image_num(self):
        return len(self.img_names)

    def _get_views(self, idx, resolution, rng, num_views):
        new_seed = rng.integers(0, 2**32) + idx
        new_rng = np.random.default_rng(new_seed)
        img_names = new_rng.choice(self.img_names, num_views, replace=False)

        views = []
        for v, img_name in enumerate(img_names):
            # Load RGB image
            scene, img_name = img_name
            rgb_image = imread_cv2(osp.join(self.ROOT, scene, "rgb", f"{img_name}.png"))
            depthmap = np.load(osp.join(self.ROOT, scene, "depth", f"{img_name}.npy"))
            depthmap[depthmap > 200] = 0.0
            depthmap = np.nan_to_num(depthmap, nan=0, posinf=0, neginf=0)

            intrinsics = np.load(osp.join(self.ROOT, scene, "cam", f"{img_name}.npz"))[
                "intrinsics"
            ]
            # camera pose is not provided, placeholder
            camera_pose = np.eye(4)

            rgb_image, depthmap, intrinsics = self._crop_resize_if_necessary(
                rgb_image, depthmap, intrinsics, resolution, rng=rng, info=img_name
            )

            views.append(
                dict(
                    img=rgb_image,
                    depthmap=depthmap.astype(np.float32),
                    camera_pose=camera_pose.astype(np.float32),
                    camera_intrinsics=intrinsics.astype(np.float32),
                    dataset="irs",
                    label=img_name,
                    instance=f"{str(idx)}_{img_name}",
                    is_metric=self.is_metric,
                    is_video=False,
                    quantile=np.array(1.0, dtype=np.float32),
                    img_mask=True,
                    ray_mask=False,
                    camera_only=False,
                    depth_only=False,
                    single_view=True,
                    reset=True,
                )
            )
        assert len(views) == num_views
        return views


import os.path as osp
import numpy as np
import os
import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))
from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2
import h5py
from tqdm import tqdm

class BlendedMVS_Multi(BaseMultiViewDataset):
    """Dataset of outdoor street scenes, 5 images each time"""

    def __init__(self, *args, ROOT, split=None, **kwargs):
        self.ROOT = ROOT
        self.video = False
        self.is_metric = False
        super().__init__(*args, **kwargs)
        # assert split is None
        self._load_data()

    def _load_data(self):
        self.data_dict = self.read_h5_file(os.path.join(self.ROOT, "new_overlap.h5"))
        self.num_imgs = sum(
            [len(self.data_dict[s]["basenames"]) for s in self.data_dict.keys()]
        )
        self.num_scenes = len(self.data_dict.keys())
        self.invalid_scenes = []
        self.is_reachable_cache = {scene: {} for scene in self.data_dict.keys()}

    def read_h5_file(self, h5_file_path):
        data_dict = {}
        self.all_ref_imgs = []
        with h5py.File(h5_file_path, "r") as f:
            for scene_dir in tqdm(f.keys()):
                group = f[scene_dir]
                basenames = group["basenames"][:]
                indices = group["indices"][:]
                values = group["values"][:]
                shape = group.attrs["shape"]
                # Reconstruct the sparse matrix
                score_matrix = np.zeros(shape, dtype=np.float32)
                score_matrix[indices[0], indices[1]] = values
                data_dict[scene_dir] = {
                    "basenames": basenames,
                    "score_matrix": self.build_adjacency_list(score_matrix),
                }
                self.all_ref_imgs.extend(
                    [(scene_dir, b) for b in range(len(basenames))]
                )
        return data_dict

    @staticmethod
    def build_adjacency_list(S, thresh=0.2):
        adjacency_list = [[] for _ in range(len(S))]
        S = S - thresh
        S[S < 0] = 0
        rows, cols = np.nonzero(S)
        for i, j in zip(rows, cols):
            adjacency_list[i].append((j, S[i][j]))
        return adjacency_list

    @staticmethod
    def is_reachable(adjacency_list, start_index, k):
        visited = set()
        stack = [start_index]
        while stack and len(visited) < k:
            node = stack.pop()
            if node not in visited:
                visited.add(node)
                for neighbor in adjacency_list[node]:
                    if neighbor[0] not in visited:
                        stack.append(neighbor[0])
        return len(visited) >= k

    @staticmethod
    def random_sequence_no_revisit_with_backtracking(
        adjacency_list, k, start_index, rng: np.random.Generator
    ):
        path = [start_index]
        visited = set([start_index])

        neighbor_iterators = []
        # Initialize the iterator for the start index
        neighbors = adjacency_list[start_index]
        neighbor_idxs = [n[0] for n in neighbors]
        neighbor_weights = [n[1] for n in neighbors]
        neighbor_idxs = rng.choice(
            neighbor_idxs,
            size=len(neighbor_idxs),
            replace=False,
            p=np.array(neighbor_weights) / np.sum(neighbor_weights),
        ).tolist()
        neighbor_iterators.append(iter(neighbor_idxs))

        while len(path) < k:
            if not neighbor_iterators:
                # No possible sequence
                return None
            current_iterator = neighbor_iterators[-1]
            try:
                next_index = next(current_iterator)
                if next_index not in visited:
                    path.append(next_index)
                    visited.add(next_index)

                    # Prepare iterator for the next node
                    neighbors = adjacency_list[next_index]
                    neighbor_idxs = [n[0] for n in neighbors]
                    neighbor_weights = [n[1] for n in neighbors]
                    neighbor_idxs = rng.choice(
                        neighbor_idxs,
                        size=len(neighbor_idxs),
                        replace=False,
                        p=np.array(neighbor_weights) / np.sum(neighbor_weights),
                    ).tolist()
                    neighbor_iterators.append(iter(neighbor_idxs))
            except StopIteration:
                # No more neighbors to try at this node, backtrack
                neighbor_iterators.pop()
                visited.remove(path.pop())
        return path

    @staticmethod
    def random_sequence_with_optional_repeats(
        adjacency_list,
        k,
        start_index,
        rng: np.random.Generator,
        max_k=None,
        max_attempts=100,
    ):
        if max_k is None:
            max_k = k
        path = [start_index]
        visited = set([start_index])
        current_index = start_index
        attempts = 0

        while len(path) < max_k and attempts < max_attempts:
            attempts += 1
            neighbors = adjacency_list[current_index]
            neighbor_idxs = [n[0] for n in neighbors]
            neighbor_weights = [n[1] for n in neighbors]

            if not neighbor_idxs:
                # No neighbors, cannot proceed further
                break

            # Try to find unvisited neighbors
            unvisited_neighbors = [
                (idx, wgt)
                for idx, wgt in zip(neighbor_idxs, neighbor_weights)
                if idx not in visited
            ]
            if unvisited_neighbors:
                # Select among unvisited neighbors
                unvisited_idxs = [idx for idx, _ in unvisited_neighbors]
                unvisited_weights = [wgt for _, wgt in unvisited_neighbors]
                probabilities = np.array(unvisited_weights) / np.sum(unvisited_weights)
                next_index = rng.choice(unvisited_idxs, p=probabilities)
                visited.add(next_index)
            else:
                # All neighbors visited, but we need to reach length max_k
                # So we can revisit nodes
                probabilities = np.array(neighbor_weights) / np.sum(neighbor_weights)
                next_index = rng.choice(neighbor_idxs, p=probabilities)

            path.append(next_index)
            current_index = next_index

        if len(set(path)) >= k:
            # If path is shorter than max_k, extend it by repeating existing elements
            while len(path) < max_k:
                # Randomly select nodes from the existing path to repeat
                next_index = rng.choice(path)
                path.append(next_index)
            return path
        else:
            # Could not reach k unique nodes
            return None

    def __len__(self):
        return len(self.all_ref_imgs)

    def get_image_num(self):
        return self.num_imgs

    def get_stats(self):
        return f"{len(self)} imgs from {self.num_scenes} scenes"

    def generate_sequence(
        self, scene, adj_list, num_views, start_index, rng, allow_repeat=False
    ):
        cutoff = num_views if not allow_repeat else max(num_views // 5, 3)
        if start_index in self.is_reachable_cache[scene]:
            if not self.is_reachable_cache[scene][start_index]:
                print(
                    f"Cannot reach {num_views} unique elements from index {start_index}."
                )
                return None
        else:
            self.is_reachable_cache[scene][start_index] = self.is_reachable(
                adj_list, start_index, cutoff
            )
            if not self.is_reachable_cache[scene][start_index]:
                print(
                    f"Cannot reach {num_views} unique elements from index {start_index}."
                )
                return None
        if not allow_repeat:
            sequence = self.random_sequence_no_revisit_with_backtracking(
                adj_list, cutoff, start_index, rng
            )
        else:
            sequence = self.random_sequence_with_optional_repeats(
                adj_list, cutoff, start_index, rng, max_k=num_views
            )
        if not sequence:
            self.is_reachable_cache[scene][start_index] = False
            print("Failed to generate a sequence without revisiting.")
        return sequence

    def _get_views(self, idx, resolution, rng: np.random.Generator, num_views):
        scene_info, ref_img_idx = self.all_ref_imgs[idx]
        invalid_seq = True
        ordered_video = False

        while invalid_seq:
            basenames = self.data_dict[scene_info]["basenames"]
            if (
                sum(
                    [
                        (1 - int(x))
                        for x in list(self.is_reachable_cache[scene_info].values())
                    ]
                )
                > len(basenames) - self.num_views
            ):
                self.invalid_scenes.append(scene_info)
            while scene_info in self.invalid_scenes:
                idx = rng.integers(low=0, high=len(self.all_ref_imgs))
                scene_info, ref_img_idx = self.all_ref_imgs[idx]
                basenames = self.data_dict[scene_info]["basenames"]

            score_matrix = self.data_dict[scene_info]["score_matrix"]
            imgs_idxs = self.generate_sequence(
                scene_info, score_matrix, num_views, ref_img_idx, rng, self.allow_repeat
            )

            if imgs_idxs is None:
                random_direction = 2 * rng.choice(2) - 1
                for offset in range(1, len(basenames)):
                    tentative_im_idx = (
                        ref_img_idx + (random_direction * offset)
                    ) % len(basenames)
                    if (
                        tentative_im_idx not in self.is_reachable_cache[scene_info]
                        or self.is_reachable_cache[scene_info][tentative_im_idx]
                    ):
                        ref_img_idx = tentative_im_idx
                        break
            else:
                invalid_seq = False
        views = []
        for view_idx in imgs_idxs:
            scene_dir = osp.join(self.ROOT, scene_info)
            impath = basenames[view_idx].decode("utf-8")
            image = imread_cv2(osp.join(scene_dir, impath + ".jpg"))
            depthmap = imread_cv2(osp.join(scene_dir, impath + ".exr"))
            camera_params = np.load(osp.join(scene_dir, impath + ".npz"))

            intrinsics = np.float32(camera_params["intrinsics"])
            camera_pose = np.eye(4, dtype=np.float32)
            camera_pose[:3, :3] = camera_params["R_cam2world"]
            camera_pose[:3, 3] = camera_params["t_cam2world"]

            image, depthmap, intrinsics = self._crop_resize_if_necessary(
                image, depthmap, intrinsics, resolution, rng, info=(scene_dir, impath)
            )

            views.append(
                dict(
                    img=image,
                    depthmap=depthmap,
                    camera_pose=camera_pose,  # cam2world
                    camera_intrinsics=intrinsics,
                    dataset="BlendedMVS",
                    label=osp.relpath(scene_dir, self.ROOT),
                    is_metric=self.is_metric,
                    is_video=ordered_video,
                    instance=osp.join(scene_dir, impath + ".jpg"),
                    quantile=np.array(0.97, dtype=np.float32),
                    img_mask=True,
                    ray_mask=False,
                    camera_only=False,
                    depth_only=False,
                    single_view=False,
                    reset=False,
                )
            )
        assert len(views) == num_views
        return views


import os.path as osp
import numpy as np
import os
import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))
from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2
import h5py
from tqdm import tqdm

class BlendedMVS_Multi(BaseMultiViewDataset):
    """Dataset of outdoor street scenes, 5 images each time"""

    def __init__(self, *args, ROOT, split=None, **kwargs):
        self.ROOT = ROOT
        self.video = False
        self.is_metric = False
        super().__init__(*args, **kwargs)
        # assert split is None
        self._load_data()

    def _load_data(self):
        self.data_dict = self.read_h5_file(os.path.join(self.ROOT, "new_overlap.h5"))
        self.num_imgs = sum(
            [len(self.data_dict[s]["basenames"]) for s in self.data_dict.keys()]
        )
        self.num_scenes = len(self.data_dict.keys())
        self.invalid_scenes = []
        self.is_reachable_cache = {scene: {} for scene in self.data_dict.keys()}

    def read_h5_file(self, h5_file_path):
        data_dict = {}
        self.all_ref_imgs = []
        with h5py.File(h5_file_path, "r") as f:
            for scene_dir in tqdm(f.keys()):
                group = f[scene_dir]
                basenames = group["basenames"][:]
                indices = group["indices"][:]
                values = group["values"][:]
                shape = group.attrs["shape"]


import sys

sys.path.append(osp.join(osp.dirname(__file__), "..", ".."))
from dust3r.datasets.base.base_multiview_dataset import BaseMultiViewDataset
from dust3r.utils.image import imread_cv2
import h5py
from tqdm import tqdm

class BlendedMVS_Multi(BaseMultiViewDataset):
    """Dataset of outdoor street scenes, 5 images each time"""

    def __init__(self, *args, ROOT, split=None, **kwargs):
        self.ROOT = ROOT
        self.video = False
        self.is_metric = False
        super().__init__(*args, **kwargs)
        # assert split is None
        self._load_data()

    def _load_data(self):
        self.data_dict = self.read_h5_file(os.path.join(self.ROOT, "new_overlap.h5"))
        self.num_imgs = sum(
            [len(self.data_dict[s]["basenames"]) for s in self.data_dict.keys()]
        )
        self.num_scenes = len(self.data_dict.keys())
        self.invalid_scenes = []
        self.is_reachable_cache = {scene: {} for scene in self.data_dict.keys()}

    def read_h5_file(self, h5_file_path):
        data_dict = {}
        self.all_ref_imgs = []
        with h5py.File(h5_file_path, "r") as f:
            for scene_dir in tqdm(f.keys()):
                group = f[scene_dir]
                basenames = group["basenames"][:]
                indices = group["indices"][:]
                values = group["values"][:]
                shape = group.attrs["shape"]
                # Reconstruct the sparse matrix
                score_matrix = np.zeros(shape, dtype=np.float32)
                score_matrix[indices[0], indices[1]] = values
                data_dict[scene_dir] = {
                    "basenames": basenames,
                    "score_matrix": self.build_adjacency_list(score_matrix),
                }
                self.all_ref_imgs.extend(
                    [(scene_dir, b) for b in range(len(basenames))]


class BlendedMVS_Multi(BaseMultiViewDataset):
    """Dataset of outdoor street scenes, 5 images each time"""

    def __init__(self, *args, ROOT, split=None, **kwargs):
        self.ROOT = ROOT
        self.video = False
        self.is_metric = False
        super().__init__(*args, **kwargs)
        # assert split is None
        self._load_data()

    def _load_data(self):
        self.data_dict = self.read_h5_file(os.path.join(self.ROOT, "new_overlap.h5"))
        self.num_imgs = sum(
            [len(self.data_dict[s]["basenames"]) for s in self.data_dict.keys()]
        )
        self.num_scenes = len(self.data_dict.keys())
        self.invalid_scenes = []
        self.is_reachable_cache = {scene: {} for scene in self.data_dict.keys()}

    def read_h5_file(self, h5_file_path):
        data_dict = {}
        self.all_ref_imgs = []
        with h5py.File(h5_file_path, "r") as f:
            for scene_dir in tqdm(f.keys()):
                group = f[scene_dir]
                basenames = group["basenames"][:]
                indices = group["indices"][:]
                values = group["values"][:]
                shape = group.attrs["shape"]
                # Reconstruct the sparse matrix
                score_matrix = np.zeros(shape, dtype=np.float32)
                score_matrix[indices[0], indices[1]] = values
                data_dict[scene_dir] = {
                    "basenames": basenames,
                    "score_matrix": self.build_adjacency_list(score_matrix),
                }
                self.all_ref_imgs.extend(
                    [(scene_dir, b) for b in range(len(basenames))]
                )
        return data_dict

    @staticmethod
    def build_adjacency_list(S, thresh=0.2):
        adjacency_list = [[] for _ in range(len(S))]
        S = S - thresh
        S[S < 0] = 0
        rows, cols = np.nonzero(S)
        for i, j in zip(rows, cols):
            adjacency_list[i].append((j, S[i][j]))
        return adjacency_list

    @staticmethod
    def is_reachable(adjacency_list, start_index, k):
        visited = set()
        stack = [start_index]
        while stack and len(visited) < k:
            node = stack.pop()
            if node not in visited:
                visited.add(node)
                for neighbor in adjacency_list[node]:


        with h5py.File(h5_file_path, "r") as f:
            for scene_dir in tqdm(f.keys()):
                group = f[scene_dir]
                basenames = group["basenames"][:]
                indices = group["indices"][:]
                values = group["values"][:]
                shape = group.attrs["shape"]
                # Reconstruct the sparse matrix
                score_matrix = np.zeros(shape, dtype=np.float32)
                score_matrix[indices[0], indices[1]] = values
                data_dict[scene_dir] = {
                    "basenames": basenames,
                    "score_matrix": self.build_adjacency_list(score_matrix),
                }
                self.all_ref_imgs.extend(
                    [(scene_dir, b) for b in range(len(basenames))]
                )
        return data_dict

    @staticmethod
    def build_adjacency_list(S, thresh=0.2):
        adjacency_list = [[] for _ in range(len(S))]
        S = S - thresh
        S[S < 0] = 0
        rows, cols = np.nonzero(S)
        for i, j in zip(rows, cols):
            adjacency_list[i].append((j, S[i][j]))
        return adjacency_list

    @staticmethod
    def is_reachable(adjacency_list, start_index, k):
        visited = set()
        stack = [start_index]
        while stack and len(visited) < k:
            node = stack.pop()
            if node not in visited:
                visited.add(node)
                for neighbor in adjacency_list[node]:
                    if neighbor[0] not in visited:
                        stack.append(neighbor[0])
        return len(visited) >= k

    @staticmethod
    def random_sequence_no_revisit_with_backtracking(
        adjacency_list, k, start_index, rng: np.random.Generator
    ):
        path = [start_index]
        visited = set([start_index])


                data_dict[scene_dir] = {
                    "basenames": basenames,
                    "score_matrix": self.build_adjacency_list(score_matrix),
                }
                self.all_ref_imgs.extend(
                    [(scene_dir, b) for b in range(len(basenames))]
                )
        return data_dict

    @staticmethod
    def build_adjacency_list(S, thresh=0.2):
        adjacency_list = [[] for _ in range(len(S))]
        S = S - thresh
        S[S < 0] = 0
        rows, cols = np.nonzero(S)
        for i, j in zip(rows, cols):
            adjacency_list[i].append((j, S[i][j]))
        return adjacency_list

    @staticmethod
    def is_reachable(adjacency_list, start_index, k):
        visited = set()
        stack = [start_index]
        while stack and len(visited) < k:
            node = stack.pop()
            if node not in visited:
                visited.add(node)
                for neighbor in adjacency_list[node]:
                    if neighbor[0] not in visited:
                        stack.append(neighbor[0])
        return len(visited) >= k

    @staticmethod
    def random_sequence_no_revisit_with_backtracking(
        adjacency_list, k, start_index, rng: np.random.Generator
    ):
        path = [start_index]
        visited = set([start_index])

        neighbor_iterators = []
        # Initialize the iterator for the start index
        neighbors = adjacency_list[start_index]
        neighbor_idxs = [n[0] for n in neighbors]
        neighbor_weights = [n[1] for n in neighbors]
        neighbor_idxs = rng.choice(
            neighbor_idxs,
            size=len(neighbor_idxs),
            replace=False,
            p=np.array(neighbor_weights) / np.sum(neighbor_weights),
        ).tolist()
        neighbor_iterators.append(iter(neighbor_idxs))


        S[S < 0] = 0
        rows, cols = np.nonzero(S)
        for i, j in zip(rows, cols):
            adjacency_list[i].append((j, S[i][j]))
        return adjacency_list

    @staticmethod
    def is_reachable(adjacency_list, start_index, k):
        visited = set()
        stack = [start_index]
        while stack and len(visited) < k:
            node = stack.pop()
            if node not in visited:
                visited.add(node)
                for neighbor in adjacency_list[node]:
                    if neighbor[0] not in visited:
                        stack.append(neighbor[0])
        return len(visited) >= k

    @staticmethod
    def random_sequence_no_revisit_with_backtracking(
        adjacency_list, k, start_index, rng: np.random.Generator
    ):
        path = [start_index]
        visited = set([start_index])

        neighbor_iterators = []
        # Initialize the iterator for the start index
        neighbors = adjacency_list[start_index]
        neighbor_idxs = [n[0] for n in neighbors]
        neighbor_weights = [n[1] for n in neighbors]
        neighbor_idxs = rng.choice(
            neighbor_idxs,
            size=len(neighbor_idxs),
            replace=False,
            p=np.array(neighbor_weights) / np.sum(neighbor_weights),
        ).tolist()
        neighbor_iterators.append(iter(neighbor_idxs))

        while len(path) < k:
            if not neighbor_iterators:
                # No possible sequence
                return None
            current_iterator = neighbor_iterators[-1]
            try:
                next_index = next(current_iterator)
                if next_index not in visited:
                    path.append(next_index)
                    visited.add(next_index)

                    # Prepare iterator for the next node
                    neighbors = adjacency_list[next_index]
                    neighbor_idxs = [n[0] for n in neighbors]
                    neighbor_weights = [n[1] for n in neighbors]
                    neighbor_idxs = rng.choice(
                        neighbor_idxs,
                        size=len(neighbor_idxs),
                        replace=False,
                        p=np.array(neighbor_weights) / np.sum(neighbor_weights),
                    ).tolist()
                    neighbor_iterators.append(iter(neighbor_idxs))
            except StopIteration:
                # No more neighbors to try at this node, backtrack
                neighbor_iterators.pop()
                visited.remove(path.pop())
        return path

    @staticmethod
    def random_sequence_with_optional_repeats(
        adjacency_list,
        k,
        start_index,
        rng: np.random.Generator,
        max_k=None,
        max_attempts=100,
    ):
        if max_k is None:
            max_k = k
        path = [start_index]
        visited = set([start_index])
        current_index = start_index
        attempts = 0

        while len(path) < max_k and attempts < max_attempts:
            attempts += 1
            neighbors = adjacency_list[current_index]