mirror of
https://github.com/nerfstudio-project/nerfstudio.git
synced 2026-11-13 11:24:00 +08:00
Depth supervision for `depth-nerfacto` was added in #1173. This patch extends that support to `sdfstudio` datasets ([as originally intended](https://github.com/nerfstudio-project/nerfstudio/issues/1173#issuecomment-1494633338_)) by adding `depth_unit_scale_factor` to `sdfstudio` metadata.
162 lines
5.8 KiB
Python
162 lines
5.8 KiB
Python
# Copyright 2022 the Regents of the University of California, Nerfstudio Team and contributors. All rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
"""Datapaser for sdfstudio formatted data"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
from typing import Type
|
|
|
|
import torch
|
|
|
|
from nerfstudio.cameras import camera_utils
|
|
from nerfstudio.cameras.cameras import Cameras, CameraType
|
|
from nerfstudio.data.dataparsers.base_dataparser import (
|
|
DataParser,
|
|
DataParserConfig,
|
|
DataparserOutputs,
|
|
)
|
|
from nerfstudio.data.scene_box import SceneBox
|
|
from nerfstudio.utils.io import load_from_json
|
|
|
|
|
|
@dataclass
|
|
class SDFStudioDataParserConfig(DataParserConfig):
|
|
"""Scene dataset parser config"""
|
|
|
|
_target: Type = field(default_factory=lambda: SDFStudio)
|
|
"""target class to instantiate"""
|
|
data: Path = Path("data/DTU/scan65")
|
|
"""Directory specifying location of data."""
|
|
include_mono_prior: bool = False
|
|
"""whether or not to load monocular depth and normal """
|
|
depth_unit_scale_factor: float = 1e-3
|
|
"""Scales the depth values to meters. Default value is 0.001 for a millimeter to meter conversion."""
|
|
include_foreground_mask: bool = False
|
|
"""whether or not to load foreground mask"""
|
|
downscale_factor: int = 1
|
|
scene_scale: float = 2.0
|
|
"""
|
|
Sets the bounding cube to have edge length of this size.
|
|
The longest dimension of the axis-aligned bbox will be scaled to this value.
|
|
"""
|
|
skip_every_for_val_split: int = 1
|
|
"""sub sampling validation images"""
|
|
auto_orient: bool = True
|
|
|
|
|
|
@dataclass
|
|
class SDFStudio(DataParser):
|
|
"""SDFStudio Dataset"""
|
|
|
|
config: SDFStudioDataParserConfig
|
|
|
|
def _generate_dataparser_outputs(self, split="train"):
|
|
# load meta data
|
|
meta = load_from_json(self.config.data / "meta_data.json")
|
|
|
|
indices = list(range(len(meta["frames"])))
|
|
# subsample to avoid out-of-memory for validation set
|
|
if split != "train" and self.config.skip_every_for_val_split >= 1:
|
|
indices = indices[:: self.config.skip_every_for_val_split]
|
|
|
|
image_filenames = []
|
|
depth_filenames = []
|
|
normal_filenames = []
|
|
transform = None
|
|
fx = []
|
|
fy = []
|
|
cx = []
|
|
cy = []
|
|
camera_to_worlds = []
|
|
for i, frame in enumerate(meta["frames"]):
|
|
if i not in indices:
|
|
continue
|
|
|
|
image_filename = self.config.data / frame["rgb_path"]
|
|
depth_filename = frame.get("mono_depth_path")
|
|
normal_filename = frame.get("mono_normal_path")
|
|
|
|
intrinsics = torch.tensor(frame["intrinsics"])
|
|
camtoworld = torch.tensor(frame["camtoworld"])
|
|
|
|
# append data
|
|
image_filenames.append(image_filename)
|
|
if depth_filename is not None and normal_filename is not None:
|
|
depth_filenames.append(self.config.data / depth_filename)
|
|
normal_filenames.append(self.config.data / normal_filename)
|
|
fx.append(intrinsics[0, 0])
|
|
fy.append(intrinsics[1, 1])
|
|
cx.append(intrinsics[0, 2])
|
|
cy.append(intrinsics[1, 2])
|
|
camera_to_worlds.append(camtoworld)
|
|
|
|
fx = torch.stack(fx)
|
|
fy = torch.stack(fy)
|
|
cx = torch.stack(cx)
|
|
cy = torch.stack(cy)
|
|
c2w_colmap = torch.stack(camera_to_worlds)
|
|
camera_to_worlds = torch.stack(camera_to_worlds)
|
|
|
|
# Convert from COLMAP's/OPENCV's camera coordinate system to nerfstudio
|
|
camera_to_worlds[:, 0:3, 1:3] *= -1
|
|
|
|
if self.config.auto_orient:
|
|
camera_to_worlds, transform = camera_utils.auto_orient_and_center_poses(
|
|
camera_to_worlds,
|
|
method="up",
|
|
center_method="none",
|
|
)
|
|
|
|
# scene box from meta data
|
|
meta_scene_box = meta["scene_box"]
|
|
aabb = torch.tensor(meta_scene_box["aabb"], dtype=torch.float32)
|
|
scene_box = SceneBox(
|
|
aabb=aabb,
|
|
)
|
|
|
|
height, width = meta["height"], meta["width"]
|
|
cameras = Cameras(
|
|
fx=fx,
|
|
fy=fy,
|
|
cx=cx,
|
|
cy=cy,
|
|
height=height,
|
|
width=width,
|
|
camera_to_worlds=camera_to_worlds[:, :3, :4],
|
|
camera_type=CameraType.PERSPECTIVE,
|
|
)
|
|
|
|
# TODO supports downsample
|
|
# cameras.rescale_output_resolution(scaling_factor=1.0 / self.config.downscale_factor)
|
|
if self.config.include_mono_prior:
|
|
assert meta["has_mono_prior"], f"no mono prior in {self.config.data}"
|
|
|
|
dataparser_outputs = DataparserOutputs(
|
|
image_filenames=image_filenames,
|
|
cameras=cameras,
|
|
scene_box=scene_box,
|
|
metadata={
|
|
"depth_filenames": depth_filenames if len(depth_filenames) > 0 else None,
|
|
"normal_filenames": normal_filenames if len(normal_filenames) > 0 else None,
|
|
"transform": transform,
|
|
# required for normal maps, these are in colmap format so they require c2w before conversion
|
|
"camera_to_worlds": c2w_colmap if len(c2w_colmap) > 0 else None,
|
|
"include_mono_prior": self.config.include_mono_prior,
|
|
"depth_unit_scale_factor": self.config.depth_unit_scale_factor,
|
|
},
|
|
)
|
|
return dataparser_outputs
|