Initial media depth project backup
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
# MIT License
|
||||
|
||||
# Copyright (c) 2022 Intelligent Systems Lab Org
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
# File author: Shariq Farooq Bhat
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
|
||||
def infer_type(x): # hacky way to infer type from string args
|
||||
if not isinstance(x, str):
|
||||
return x
|
||||
|
||||
try:
|
||||
x = int(x)
|
||||
return x
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
x = float(x)
|
||||
return x
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return x
|
||||
|
||||
|
||||
def parse_unknown(unknown_args):
|
||||
clean = []
|
||||
for a in unknown_args:
|
||||
if "=" in a:
|
||||
k, v = a.split("=")
|
||||
clean.extend([k, v])
|
||||
else:
|
||||
clean.append(a)
|
||||
|
||||
keys = clean[::2]
|
||||
values = clean[1::2]
|
||||
return {k.replace("--", ""): infer_type(v) for k, v in zip(keys, values)}
|
||||
437
Depth-Anything-V1-main/metric_depth/zoedepth/utils/config.py
Normal file
437
Depth-Anything-V1-main/metric_depth/zoedepth/utils/config.py
Normal file
@@ -0,0 +1,437 @@
|
||||
# MIT License
|
||||
|
||||
# Copyright (c) 2022 Intelligent Systems Lab Org
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
# File author: Shariq Farooq Bhat
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
from zoedepth.utils.easydict import EasyDict as edict
|
||||
|
||||
from zoedepth.utils.arg_utils import infer_type
|
||||
import pathlib
|
||||
import platform
|
||||
|
||||
ROOT = pathlib.Path(__file__).parent.parent.resolve()
|
||||
|
||||
HOME_DIR = os.path.expanduser("./data")
|
||||
|
||||
COMMON_CONFIG = {
|
||||
"save_dir": os.path.expanduser("./depth_anything_finetune"),
|
||||
"project": "ZoeDepth",
|
||||
"tags": '',
|
||||
"notes": "",
|
||||
"gpu": None,
|
||||
"root": ".",
|
||||
"uid": None,
|
||||
"print_losses": False
|
||||
}
|
||||
|
||||
DATASETS_CONFIG = {
|
||||
"kitti": {
|
||||
"dataset": "kitti",
|
||||
"min_depth": 0.001,
|
||||
"max_depth": 80,
|
||||
"data_path": os.path.join(HOME_DIR, "Kitti/raw_data"),
|
||||
"gt_path": os.path.join(HOME_DIR, "Kitti/data_depth_annotated_zoedepth"),
|
||||
"filenames_file": "./train_test_inputs/kitti_eigen_train_files_with_gt.txt",
|
||||
"input_height": 352,
|
||||
"input_width": 1216, # 704
|
||||
"data_path_eval": os.path.join(HOME_DIR, "Kitti/raw_data"),
|
||||
"gt_path_eval": os.path.join(HOME_DIR, "Kitti/data_depth_annotated_zoedepth"),
|
||||
"filenames_file_eval": "./train_test_inputs/kitti_eigen_test_files_with_gt.txt",
|
||||
|
||||
"min_depth_eval": 1e-3,
|
||||
"max_depth_eval": 80,
|
||||
|
||||
"do_random_rotate": True,
|
||||
"degree": 1.0,
|
||||
"do_kb_crop": True,
|
||||
"garg_crop": True,
|
||||
"eigen_crop": False,
|
||||
"use_right": False
|
||||
},
|
||||
"kitti_test": {
|
||||
"dataset": "kitti",
|
||||
"min_depth": 0.001,
|
||||
"max_depth": 80,
|
||||
"data_path": os.path.join(HOME_DIR, "Kitti/raw_data"),
|
||||
"gt_path": os.path.join(HOME_DIR, "Kitti/data_depth_annotated_zoedepth"),
|
||||
"filenames_file": "./train_test_inputs/kitti_eigen_train_files_with_gt.txt",
|
||||
"input_height": 352,
|
||||
"input_width": 1216,
|
||||
"data_path_eval": os.path.join(HOME_DIR, "Kitti/raw_data"),
|
||||
"gt_path_eval": os.path.join(HOME_DIR, "Kitti/data_depth_annotated_zoedepth"),
|
||||
"filenames_file_eval": "./train_test_inputs/kitti_eigen_test_files_with_gt.txt",
|
||||
|
||||
"min_depth_eval": 1e-3,
|
||||
"max_depth_eval": 80,
|
||||
|
||||
"do_random_rotate": False,
|
||||
"degree": 1.0,
|
||||
"do_kb_crop": True,
|
||||
"garg_crop": True,
|
||||
"eigen_crop": False,
|
||||
"use_right": False
|
||||
},
|
||||
"nyu": {
|
||||
"dataset": "nyu",
|
||||
"avoid_boundary": False,
|
||||
"min_depth": 1e-3, # originally 0.1
|
||||
"max_depth": 10,
|
||||
"data_path": os.path.join(HOME_DIR, "nyu"),
|
||||
"gt_path": os.path.join(HOME_DIR, "nyu"),
|
||||
"filenames_file": "./train_test_inputs/nyudepthv2_train_files_with_gt.txt",
|
||||
"input_height": 480,
|
||||
"input_width": 640,
|
||||
"data_path_eval": os.path.join(HOME_DIR, "nyu"),
|
||||
"gt_path_eval": os.path.join(HOME_DIR, "nyu"),
|
||||
"filenames_file_eval": "./train_test_inputs/nyudepthv2_test_files_with_gt.txt",
|
||||
"min_depth_eval": 1e-3,
|
||||
"max_depth_eval": 10,
|
||||
"min_depth_diff": -10,
|
||||
"max_depth_diff": 10,
|
||||
|
||||
"do_random_rotate": True,
|
||||
"degree": 1.0,
|
||||
"do_kb_crop": False,
|
||||
"garg_crop": False,
|
||||
"eigen_crop": True
|
||||
},
|
||||
"ibims": {
|
||||
"dataset": "ibims",
|
||||
"ibims_root": os.path.join(HOME_DIR, "iBims1/m1455541/ibims1_core_raw/"),
|
||||
"eigen_crop": True,
|
||||
"garg_crop": False,
|
||||
"do_kb_crop": False,
|
||||
"min_depth_eval": 0,
|
||||
"max_depth_eval": 10,
|
||||
"min_depth": 1e-3,
|
||||
"max_depth": 10
|
||||
},
|
||||
"sunrgbd": {
|
||||
"dataset": "sunrgbd",
|
||||
"sunrgbd_root": os.path.join(HOME_DIR, "SUNRGB-D"),
|
||||
"eigen_crop": True,
|
||||
"garg_crop": False,
|
||||
"do_kb_crop": False,
|
||||
"min_depth_eval": 0,
|
||||
"max_depth_eval": 8,
|
||||
"min_depth": 1e-3,
|
||||
"max_depth": 10
|
||||
},
|
||||
"diml_indoor": {
|
||||
"dataset": "diml_indoor",
|
||||
"diml_indoor_root": os.path.join(HOME_DIR, "DIML/indoor/sample/testset/"),
|
||||
"eigen_crop": True,
|
||||
"garg_crop": False,
|
||||
"do_kb_crop": False,
|
||||
"min_depth_eval": 0,
|
||||
"max_depth_eval": 10,
|
||||
"min_depth": 1e-3,
|
||||
"max_depth": 10
|
||||
},
|
||||
"diml_outdoor": {
|
||||
"dataset": "diml_outdoor",
|
||||
"diml_outdoor_root": os.path.join(HOME_DIR, "DIML/outdoor/test/LR"),
|
||||
"eigen_crop": False,
|
||||
"garg_crop": True,
|
||||
"do_kb_crop": False,
|
||||
"min_depth_eval": 2,
|
||||
"max_depth_eval": 80,
|
||||
"min_depth": 1e-3,
|
||||
"max_depth": 80
|
||||
},
|
||||
"diode_indoor": {
|
||||
"dataset": "diode_indoor",
|
||||
"diode_indoor_root": os.path.join(HOME_DIR, "DIODE/val/indoors/"),
|
||||
"eigen_crop": True,
|
||||
"garg_crop": False,
|
||||
"do_kb_crop": False,
|
||||
"min_depth_eval": 1e-3,
|
||||
"max_depth_eval": 10,
|
||||
"min_depth": 1e-3,
|
||||
"max_depth": 10
|
||||
},
|
||||
"diode_outdoor": {
|
||||
"dataset": "diode_outdoor",
|
||||
"diode_outdoor_root": os.path.join(HOME_DIR, "DIODE/val/outdoor/"),
|
||||
"eigen_crop": False,
|
||||
"garg_crop": True,
|
||||
"do_kb_crop": False,
|
||||
"min_depth_eval": 1e-3,
|
||||
"max_depth_eval": 80,
|
||||
"min_depth": 1e-3,
|
||||
"max_depth": 80
|
||||
},
|
||||
"hypersim_test": {
|
||||
"dataset": "hypersim_test",
|
||||
"hypersim_test_root": os.path.join(HOME_DIR, "HyperSim/"),
|
||||
"eigen_crop": True,
|
||||
"garg_crop": False,
|
||||
"do_kb_crop": False,
|
||||
"min_depth_eval": 1e-3,
|
||||
"max_depth_eval": 80,
|
||||
"min_depth": 1e-3,
|
||||
"max_depth": 10
|
||||
},
|
||||
"vkitti": {
|
||||
"dataset": "vkitti",
|
||||
"vkitti_root": os.path.join(HOME_DIR, "shortcuts/datasets/vkitti_test/"),
|
||||
"eigen_crop": False,
|
||||
"garg_crop": True,
|
||||
"do_kb_crop": True,
|
||||
"min_depth_eval": 1e-3,
|
||||
"max_depth_eval": 80,
|
||||
"min_depth": 1e-3,
|
||||
"max_depth": 80
|
||||
},
|
||||
"vkitti2": {
|
||||
"dataset": "vkitti2",
|
||||
"vkitti2_root": os.path.join(HOME_DIR, "vKitti2/"),
|
||||
"eigen_crop": False,
|
||||
"garg_crop": True,
|
||||
"do_kb_crop": True,
|
||||
"min_depth_eval": 1e-3,
|
||||
"max_depth_eval": 80,
|
||||
"min_depth": 1e-3,
|
||||
"max_depth": 80,
|
||||
},
|
||||
"ddad": {
|
||||
"dataset": "ddad",
|
||||
"ddad_root": os.path.join(HOME_DIR, "shortcuts/datasets/ddad/ddad_val/"),
|
||||
"eigen_crop": False,
|
||||
"garg_crop": True,
|
||||
"do_kb_crop": True,
|
||||
"min_depth_eval": 1e-3,
|
||||
"max_depth_eval": 80,
|
||||
"min_depth": 1e-3,
|
||||
"max_depth": 80,
|
||||
},
|
||||
}
|
||||
|
||||
ALL_INDOOR = ["nyu", "ibims", "sunrgbd", "diode_indoor", "hypersim_test"]
|
||||
ALL_OUTDOOR = ["kitti", "diml_outdoor", "diode_outdoor", "vkitti2", "ddad"]
|
||||
ALL_EVAL_DATASETS = ALL_INDOOR + ALL_OUTDOOR
|
||||
|
||||
COMMON_TRAINING_CONFIG = {
|
||||
"dataset": "nyu",
|
||||
"distributed": True,
|
||||
"workers": 16,
|
||||
"clip_grad": 0.1,
|
||||
"use_shared_dict": False,
|
||||
"shared_dict": None,
|
||||
"use_amp": False,
|
||||
|
||||
"aug": True,
|
||||
"random_crop": False,
|
||||
"random_translate": False,
|
||||
"translate_prob": 0.2,
|
||||
"max_translation": 100,
|
||||
|
||||
"validate_every": 0.25,
|
||||
"log_images_every": 0.1,
|
||||
"prefetch": False,
|
||||
}
|
||||
|
||||
|
||||
def flatten(config, except_keys=('bin_conf')):
|
||||
def recurse(inp):
|
||||
if isinstance(inp, dict):
|
||||
for key, value in inp.items():
|
||||
if key in except_keys:
|
||||
yield (key, value)
|
||||
if isinstance(value, dict):
|
||||
yield from recurse(value)
|
||||
else:
|
||||
yield (key, value)
|
||||
|
||||
return dict(list(recurse(config)))
|
||||
|
||||
|
||||
def split_combined_args(kwargs):
|
||||
"""Splits the arguments that are combined with '__' into multiple arguments.
|
||||
Combined arguments should have equal number of keys and values.
|
||||
Keys are separated by '__' and Values are separated with ';'.
|
||||
For example, '__n_bins__lr=256;0.001'
|
||||
|
||||
Args:
|
||||
kwargs (dict): key-value pairs of arguments where key-value is optionally combined according to the above format.
|
||||
|
||||
Returns:
|
||||
dict: Parsed dict with the combined arguments split into individual key-value pairs.
|
||||
"""
|
||||
new_kwargs = dict(kwargs)
|
||||
for key, value in kwargs.items():
|
||||
if key.startswith("__"):
|
||||
keys = key.split("__")[1:]
|
||||
values = value.split(";")
|
||||
assert len(keys) == len(
|
||||
values), f"Combined arguments should have equal number of keys and values. Keys are separated by '__' and Values are separated with ';'. For example, '__n_bins__lr=256;0.001. Given (keys,values) is ({keys}, {values})"
|
||||
for k, v in zip(keys, values):
|
||||
new_kwargs[k] = v
|
||||
return new_kwargs
|
||||
|
||||
|
||||
def parse_list(config, key, dtype=int):
|
||||
"""Parse a list of values for the key if the value is a string. The values are separated by a comma.
|
||||
Modifies the config in place.
|
||||
"""
|
||||
if key in config:
|
||||
if isinstance(config[key], str):
|
||||
config[key] = list(map(dtype, config[key].split(',')))
|
||||
assert isinstance(config[key], list) and all([isinstance(e, dtype) for e in config[key]]
|
||||
), f"{key} should be a list of values dtype {dtype}. Given {config[key]} of type {type(config[key])} with values of type {[type(e) for e in config[key]]}."
|
||||
|
||||
|
||||
def get_model_config(model_name, model_version=None):
|
||||
"""Find and parse the .json config file for the model.
|
||||
|
||||
Args:
|
||||
model_name (str): name of the model. The config file should be named config_{model_name}[_{model_version}].json under the models/{model_name} directory.
|
||||
model_version (str, optional): Specific config version. If specified config_{model_name}_{model_version}.json is searched for and used. Otherwise config_{model_name}.json is used. Defaults to None.
|
||||
|
||||
Returns:
|
||||
easydict: the config dictionary for the model.
|
||||
"""
|
||||
config_fname = f"config_{model_name}_{model_version}.json" if model_version is not None else f"config_{model_name}.json"
|
||||
config_file = os.path.join(ROOT, "models", model_name, config_fname)
|
||||
if not os.path.exists(config_file):
|
||||
return None
|
||||
|
||||
with open(config_file, "r") as f:
|
||||
config = edict(json.load(f))
|
||||
|
||||
# handle dictionary inheritance
|
||||
# only training config is supported for inheritance
|
||||
if "inherit" in config.train and config.train.inherit is not None:
|
||||
inherit_config = get_model_config(config.train["inherit"]).train
|
||||
for key, value in inherit_config.items():
|
||||
if key not in config.train:
|
||||
config.train[key] = value
|
||||
return edict(config)
|
||||
|
||||
|
||||
def update_model_config(config, mode, model_name, model_version=None, strict=False):
|
||||
model_config = get_model_config(model_name, model_version)
|
||||
if model_config is not None:
|
||||
config = {**config, **
|
||||
flatten({**model_config.model, **model_config[mode]})}
|
||||
elif strict:
|
||||
raise ValueError(f"Config file for model {model_name} not found.")
|
||||
return config
|
||||
|
||||
|
||||
def check_choices(name, value, choices):
|
||||
# return # No checks in dev branch
|
||||
if value not in choices:
|
||||
raise ValueError(f"{name} {value} not in supported choices {choices}")
|
||||
|
||||
|
||||
KEYS_TYPE_BOOL = ["use_amp", "distributed", "use_shared_dict", "same_lr", "aug", "three_phase",
|
||||
"prefetch", "cycle_momentum"] # Casting is not necessary as their int casted values in config are 0 or 1
|
||||
|
||||
|
||||
def get_config(model_name, mode='train', dataset=None, **overwrite_kwargs):
|
||||
"""Main entry point to get the config for the model.
|
||||
|
||||
Args:
|
||||
model_name (str): name of the desired model.
|
||||
mode (str, optional): "train" or "infer". Defaults to 'train'.
|
||||
dataset (str, optional): If specified, the corresponding dataset configuration is loaded as well. Defaults to None.
|
||||
|
||||
Keyword Args: key-value pairs of arguments to overwrite the default config.
|
||||
|
||||
The order of precedence for overwriting the config is (Higher precedence first):
|
||||
# 1. overwrite_kwargs
|
||||
# 2. "config_version": Config file version if specified in overwrite_kwargs. The corresponding config loaded is config_{model_name}_{config_version}.json
|
||||
# 3. "version_name": Default Model version specific config specified in overwrite_kwargs. The corresponding config loaded is config_{model_name}_{version_name}.json
|
||||
# 4. common_config: Default config for all models specified in COMMON_CONFIG
|
||||
|
||||
Returns:
|
||||
easydict: The config dictionary for the model.
|
||||
"""
|
||||
|
||||
|
||||
check_choices("Model", model_name, ["zoedepth", "zoedepth_nk"])
|
||||
check_choices("Mode", mode, ["train", "infer", "eval"])
|
||||
if mode == "train":
|
||||
check_choices("Dataset", dataset, ["nyu", "kitti", "mix", None])
|
||||
|
||||
config = flatten({**COMMON_CONFIG, **COMMON_TRAINING_CONFIG})
|
||||
config = update_model_config(config, mode, model_name)
|
||||
|
||||
# update with model version specific config
|
||||
version_name = overwrite_kwargs.get("version_name", config["version_name"])
|
||||
config = update_model_config(config, mode, model_name, version_name)
|
||||
|
||||
# update with config version if specified
|
||||
config_version = overwrite_kwargs.get("config_version", None)
|
||||
if config_version is not None:
|
||||
print("Overwriting config with config_version", config_version)
|
||||
config = update_model_config(config, mode, model_name, config_version)
|
||||
|
||||
# update with overwrite_kwargs
|
||||
# Combined args are useful for hyperparameter search
|
||||
overwrite_kwargs = split_combined_args(overwrite_kwargs)
|
||||
config = {**config, **overwrite_kwargs}
|
||||
|
||||
# Casting to bool # TODO: Not necessary. Remove and test
|
||||
for key in KEYS_TYPE_BOOL:
|
||||
if key in config:
|
||||
config[key] = bool(config[key])
|
||||
|
||||
# Model specific post processing of config
|
||||
parse_list(config, "n_attractors")
|
||||
|
||||
# adjust n_bins for each bin configuration if bin_conf is given and n_bins is passed in overwrite_kwargs
|
||||
if 'bin_conf' in config and 'n_bins' in overwrite_kwargs:
|
||||
bin_conf = config['bin_conf'] # list of dicts
|
||||
n_bins = overwrite_kwargs['n_bins']
|
||||
new_bin_conf = []
|
||||
for conf in bin_conf:
|
||||
conf['n_bins'] = n_bins
|
||||
new_bin_conf.append(conf)
|
||||
config['bin_conf'] = new_bin_conf
|
||||
|
||||
if mode == "train":
|
||||
orig_dataset = dataset
|
||||
if dataset == "mix":
|
||||
dataset = 'nyu' # Use nyu as default for mix. Dataset config is changed accordingly while loading the dataloader
|
||||
if dataset is not None:
|
||||
config['project'] = f"MonoDepth3-{orig_dataset}" # Set project for wandb
|
||||
|
||||
if dataset is not None:
|
||||
config['dataset'] = dataset
|
||||
config = {**DATASETS_CONFIG[dataset], **config}
|
||||
|
||||
|
||||
config['model'] = model_name
|
||||
typed_config = {k: infer_type(v) for k, v in config.items()}
|
||||
# add hostname to config
|
||||
config['hostname'] = platform.node()
|
||||
return edict(typed_config)
|
||||
|
||||
|
||||
def change_dataset(config, new_dataset):
|
||||
config.update(DATASETS_CONFIG[new_dataset])
|
||||
return config
|
||||
@@ -0,0 +1,158 @@
|
||||
"""
|
||||
EasyDict
|
||||
Copy/pasted from https://github.com/makinacorpus/easydict
|
||||
Original author: Mathieu Leplatre <mathieu.leplatre@makina-corpus.com>
|
||||
"""
|
||||
|
||||
class EasyDict(dict):
|
||||
"""
|
||||
Get attributes
|
||||
|
||||
>>> d = EasyDict({'foo':3})
|
||||
>>> d['foo']
|
||||
3
|
||||
>>> d.foo
|
||||
3
|
||||
>>> d.bar
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
AttributeError: 'EasyDict' object has no attribute 'bar'
|
||||
|
||||
Works recursively
|
||||
|
||||
>>> d = EasyDict({'foo':3, 'bar':{'x':1, 'y':2}})
|
||||
>>> isinstance(d.bar, dict)
|
||||
True
|
||||
>>> d.bar.x
|
||||
1
|
||||
|
||||
Bullet-proof
|
||||
|
||||
>>> EasyDict({})
|
||||
{}
|
||||
>>> EasyDict(d={})
|
||||
{}
|
||||
>>> EasyDict(None)
|
||||
{}
|
||||
>>> d = {'a': 1}
|
||||
>>> EasyDict(**d)
|
||||
{'a': 1}
|
||||
>>> EasyDict((('a', 1), ('b', 2)))
|
||||
{'a': 1, 'b': 2}
|
||||
|
||||
Set attributes
|
||||
|
||||
>>> d = EasyDict()
|
||||
>>> d.foo = 3
|
||||
>>> d.foo
|
||||
3
|
||||
>>> d.bar = {'prop': 'value'}
|
||||
>>> d.bar.prop
|
||||
'value'
|
||||
>>> d
|
||||
{'foo': 3, 'bar': {'prop': 'value'}}
|
||||
>>> d.bar.prop = 'newer'
|
||||
>>> d.bar.prop
|
||||
'newer'
|
||||
|
||||
|
||||
Values extraction
|
||||
|
||||
>>> d = EasyDict({'foo':0, 'bar':[{'x':1, 'y':2}, {'x':3, 'y':4}]})
|
||||
>>> isinstance(d.bar, list)
|
||||
True
|
||||
>>> from operator import attrgetter
|
||||
>>> list(map(attrgetter('x'), d.bar))
|
||||
[1, 3]
|
||||
>>> list(map(attrgetter('y'), d.bar))
|
||||
[2, 4]
|
||||
>>> d = EasyDict()
|
||||
>>> list(d.keys())
|
||||
[]
|
||||
>>> d = EasyDict(foo=3, bar=dict(x=1, y=2))
|
||||
>>> d.foo
|
||||
3
|
||||
>>> d.bar.x
|
||||
1
|
||||
|
||||
Still like a dict though
|
||||
|
||||
>>> o = EasyDict({'clean':True})
|
||||
>>> list(o.items())
|
||||
[('clean', True)]
|
||||
|
||||
And like a class
|
||||
|
||||
>>> class Flower(EasyDict):
|
||||
... power = 1
|
||||
...
|
||||
>>> f = Flower()
|
||||
>>> f.power
|
||||
1
|
||||
>>> f = Flower({'height': 12})
|
||||
>>> f.height
|
||||
12
|
||||
>>> f['power']
|
||||
1
|
||||
>>> sorted(f.keys())
|
||||
['height', 'power']
|
||||
|
||||
update and pop items
|
||||
>>> d = EasyDict(a=1, b='2')
|
||||
>>> e = EasyDict(c=3.0, a=9.0)
|
||||
>>> d.update(e)
|
||||
>>> d.c
|
||||
3.0
|
||||
>>> d['c']
|
||||
3.0
|
||||
>>> d.get('c')
|
||||
3.0
|
||||
>>> d.update(a=4, b=4)
|
||||
>>> d.b
|
||||
4
|
||||
>>> d.pop('a')
|
||||
4
|
||||
>>> d.a
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
AttributeError: 'EasyDict' object has no attribute 'a'
|
||||
"""
|
||||
def __init__(self, d=None, **kwargs):
|
||||
if d is None:
|
||||
d = {}
|
||||
else:
|
||||
d = dict(d)
|
||||
if kwargs:
|
||||
d.update(**kwargs)
|
||||
for k, v in d.items():
|
||||
setattr(self, k, v)
|
||||
# Class attributes
|
||||
for k in self.__class__.__dict__.keys():
|
||||
if not (k.startswith('__') and k.endswith('__')) and not k in ('update', 'pop'):
|
||||
setattr(self, k, getattr(self, k))
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if isinstance(value, (list, tuple)):
|
||||
value = [self.__class__(x)
|
||||
if isinstance(x, dict) else x for x in value]
|
||||
elif isinstance(value, dict) and not isinstance(value, self.__class__):
|
||||
value = self.__class__(value)
|
||||
super(EasyDict, self).__setattr__(name, value)
|
||||
super(EasyDict, self).__setitem__(name, value)
|
||||
|
||||
__setitem__ = __setattr__
|
||||
|
||||
def update(self, e=None, **f):
|
||||
d = e or dict()
|
||||
d.update(f)
|
||||
for k in d:
|
||||
setattr(self, k, d[k])
|
||||
|
||||
def pop(self, k, d=None):
|
||||
delattr(self, k)
|
||||
return super(EasyDict, self).pop(k, d)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
@@ -0,0 +1,98 @@
|
||||
# MIT License
|
||||
|
||||
# Copyright (c) 2022 Intelligent Systems Lab Org
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
# File author: Shariq Farooq Bhat
|
||||
|
||||
import numpy as np
|
||||
|
||||
def get_intrinsics(H,W):
|
||||
"""
|
||||
Intrinsics for a pinhole camera model.
|
||||
Assume fov of 55 degrees and central principal point.
|
||||
"""
|
||||
f = 0.5 * W / np.tan(0.5 * 55 * np.pi / 180.0)
|
||||
cx = 0.5 * W
|
||||
cy = 0.5 * H
|
||||
return np.array([[f, 0, cx],
|
||||
[0, f, cy],
|
||||
[0, 0, 1]])
|
||||
|
||||
def depth_to_points(depth, R=None, t=None):
|
||||
|
||||
K = get_intrinsics(depth.shape[1], depth.shape[2])
|
||||
Kinv = np.linalg.inv(K)
|
||||
if R is None:
|
||||
R = np.eye(3)
|
||||
if t is None:
|
||||
t = np.zeros(3)
|
||||
|
||||
# M converts from your coordinate to PyTorch3D's coordinate system
|
||||
M = np.eye(3)
|
||||
M[0, 0] = -1.0
|
||||
M[1, 1] = -1.0
|
||||
|
||||
height, width = depth.shape[1:3]
|
||||
|
||||
x = np.arange(width)
|
||||
y = np.arange(height)
|
||||
coord = np.stack(np.meshgrid(x, y), -1)
|
||||
coord = np.concatenate((coord, np.ones_like(coord)[:, :, [0]]), -1) # z=1
|
||||
coord = coord.astype(np.float32)
|
||||
# coord = torch.as_tensor(coord, dtype=torch.float32, device=device)
|
||||
coord = coord[None] # bs, h, w, 3
|
||||
|
||||
D = depth[:, :, :, None, None]
|
||||
# print(D.shape, Kinv[None, None, None, ...].shape, coord[:, :, :, :, None].shape )
|
||||
pts3D_1 = D * Kinv[None, None, None, ...] @ coord[:, :, :, :, None]
|
||||
# pts3D_1 live in your coordinate system. Convert them to Py3D's
|
||||
pts3D_1 = M[None, None, None, ...] @ pts3D_1
|
||||
# from reference to targe tviewpoint
|
||||
pts3D_2 = R[None, None, None, ...] @ pts3D_1 + t[None, None, None, :, None]
|
||||
# pts3D_2 = pts3D_1
|
||||
# depth_2 = pts3D_2[:, :, :, 2, :] # b,1,h,w
|
||||
return pts3D_2[:, :, :, :3, 0][0]
|
||||
|
||||
|
||||
def create_triangles(h, w, mask=None):
|
||||
"""
|
||||
Reference: https://github.com/google-research/google-research/blob/e96197de06613f1b027d20328e06d69829fa5a89/infinite_nature/render_utils.py#L68
|
||||
Creates mesh triangle indices from a given pixel grid size.
|
||||
This function is not and need not be differentiable as triangle indices are
|
||||
fixed.
|
||||
Args:
|
||||
h: (int) denoting the height of the image.
|
||||
w: (int) denoting the width of the image.
|
||||
Returns:
|
||||
triangles: 2D numpy array of indices (int) with shape (2(W-1)(H-1) x 3)
|
||||
"""
|
||||
x, y = np.meshgrid(range(w - 1), range(h - 1))
|
||||
tl = y * w + x
|
||||
tr = y * w + x + 1
|
||||
bl = (y + 1) * w + x
|
||||
br = (y + 1) * w + x + 1
|
||||
triangles = np.array([tl, bl, tr, br, tr, bl])
|
||||
triangles = np.transpose(triangles, (1, 2, 0)).reshape(
|
||||
((w - 1) * (h - 1) * 2, 3))
|
||||
if mask is not None:
|
||||
mask = mask.reshape(-1)
|
||||
triangles = triangles[mask[triangles].all(1)]
|
||||
return triangles
|
||||
368
Depth-Anything-V1-main/metric_depth/zoedepth/utils/misc.py
Normal file
368
Depth-Anything-V1-main/metric_depth/zoedepth/utils/misc.py
Normal file
@@ -0,0 +1,368 @@
|
||||
# MIT License
|
||||
|
||||
# Copyright (c) 2022 Intelligent Systems Lab Org
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
# File author: Shariq Farooq Bhat
|
||||
|
||||
"""Miscellaneous utility functions."""
|
||||
|
||||
from scipy import ndimage
|
||||
|
||||
import base64
|
||||
import math
|
||||
import re
|
||||
from io import BytesIO
|
||||
|
||||
import matplotlib
|
||||
import matplotlib.cm
|
||||
import numpy as np
|
||||
import requests
|
||||
import torch
|
||||
import torch.distributed as dist
|
||||
import torch.nn
|
||||
import torch.nn as nn
|
||||
import torch.utils.data.distributed
|
||||
from PIL import Image
|
||||
from torchvision.transforms import ToTensor
|
||||
|
||||
|
||||
class RunningAverage:
|
||||
def __init__(self):
|
||||
self.avg = 0
|
||||
self.count = 0
|
||||
|
||||
def append(self, value):
|
||||
self.avg = (value + self.count * self.avg) / (self.count + 1)
|
||||
self.count += 1
|
||||
|
||||
def get_value(self):
|
||||
return self.avg
|
||||
|
||||
|
||||
def denormalize(x):
|
||||
"""Reverses the imagenet normalization applied to the input.
|
||||
|
||||
Args:
|
||||
x (torch.Tensor - shape(N,3,H,W)): input tensor
|
||||
|
||||
Returns:
|
||||
torch.Tensor - shape(N,3,H,W): Denormalized input
|
||||
"""
|
||||
mean = torch.Tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1).to(x.device)
|
||||
std = torch.Tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1).to(x.device)
|
||||
return x * std + mean
|
||||
|
||||
|
||||
class RunningAverageDict:
|
||||
"""A dictionary of running averages."""
|
||||
def __init__(self):
|
||||
self._dict = None
|
||||
|
||||
def update(self, new_dict):
|
||||
if new_dict is None:
|
||||
return
|
||||
|
||||
if self._dict is None:
|
||||
self._dict = dict()
|
||||
for key, value in new_dict.items():
|
||||
self._dict[key] = RunningAverage()
|
||||
|
||||
for key, value in new_dict.items():
|
||||
self._dict[key].append(value)
|
||||
|
||||
def get_value(self):
|
||||
if self._dict is None:
|
||||
return None
|
||||
return {key: value.get_value() for key, value in self._dict.items()}
|
||||
|
||||
|
||||
def colorize(value, vmin=None, vmax=None, cmap='gray_r', invalid_val=-99, invalid_mask=None, background_color=(128, 128, 128, 255), gamma_corrected=False, value_transform=None):
|
||||
"""Converts a depth map to a color image.
|
||||
|
||||
Args:
|
||||
value (torch.Tensor, numpy.ndarry): Input depth map. Shape: (H, W) or (1, H, W) or (1, 1, H, W). All singular dimensions are squeezed
|
||||
vmin (float, optional): vmin-valued entries are mapped to start color of cmap. If None, value.min() is used. Defaults to None.
|
||||
vmax (float, optional): vmax-valued entries are mapped to end color of cmap. If None, value.max() is used. Defaults to None.
|
||||
cmap (str, optional): matplotlib colormap to use. Defaults to 'magma_r'.
|
||||
invalid_val (int, optional): Specifies value of invalid pixels that should be colored as 'background_color'. Defaults to -99.
|
||||
invalid_mask (numpy.ndarray, optional): Boolean mask for invalid regions. Defaults to None.
|
||||
background_color (tuple[int], optional): 4-tuple RGB color to give to invalid pixels. Defaults to (128, 128, 128, 255).
|
||||
gamma_corrected (bool, optional): Apply gamma correction to colored image. Defaults to False.
|
||||
value_transform (Callable, optional): Apply transform function to valid pixels before coloring. Defaults to None.
|
||||
|
||||
Returns:
|
||||
numpy.ndarray, dtype - uint8: Colored depth map. Shape: (H, W, 4)
|
||||
"""
|
||||
if isinstance(value, torch.Tensor):
|
||||
value = value.detach().cpu().numpy()
|
||||
|
||||
value = value.squeeze()
|
||||
if invalid_mask is None:
|
||||
invalid_mask = value == invalid_val
|
||||
mask = np.logical_not(invalid_mask)
|
||||
|
||||
# normalize
|
||||
vmin = np.percentile(value[mask],2) if vmin is None else vmin
|
||||
vmax = np.percentile(value[mask],85) if vmax is None else vmax
|
||||
if vmin != vmax:
|
||||
value = (value - vmin) / (vmax - vmin) # vmin..vmax
|
||||
else:
|
||||
# Avoid 0-division
|
||||
value = value * 0.
|
||||
|
||||
# squeeze last dim if it exists
|
||||
# grey out the invalid values
|
||||
|
||||
value[invalid_mask] = np.nan
|
||||
cmapper = matplotlib.cm.get_cmap(cmap)
|
||||
if value_transform:
|
||||
value = value_transform(value)
|
||||
# value = value / value.max()
|
||||
value = cmapper(value, bytes=True) # (nxmx4)
|
||||
|
||||
# img = value[:, :, :]
|
||||
img = value[...]
|
||||
img[invalid_mask] = background_color
|
||||
|
||||
# return img.transpose((2, 0, 1))
|
||||
if gamma_corrected:
|
||||
# gamma correction
|
||||
img = img / 255
|
||||
img = np.power(img, 2.2)
|
||||
img = img * 255
|
||||
img = img.astype(np.uint8)
|
||||
return img
|
||||
|
||||
|
||||
def count_parameters(model, include_all=False):
|
||||
return sum(p.numel() for p in model.parameters() if p.requires_grad or include_all)
|
||||
|
||||
|
||||
def compute_errors(gt, pred):
|
||||
"""Compute metrics for 'pred' compared to 'gt'
|
||||
|
||||
Args:
|
||||
gt (numpy.ndarray): Ground truth values
|
||||
pred (numpy.ndarray): Predicted values
|
||||
|
||||
gt.shape should be equal to pred.shape
|
||||
|
||||
Returns:
|
||||
dict: Dictionary containing the following metrics:
|
||||
'a1': Delta1 accuracy: Fraction of pixels that are within a scale factor of 1.25
|
||||
'a2': Delta2 accuracy: Fraction of pixels that are within a scale factor of 1.25^2
|
||||
'a3': Delta3 accuracy: Fraction of pixels that are within a scale factor of 1.25^3
|
||||
'abs_rel': Absolute relative error
|
||||
'rmse': Root mean squared error
|
||||
'log_10': Absolute log10 error
|
||||
'sq_rel': Squared relative error
|
||||
'rmse_log': Root mean squared error on the log scale
|
||||
'silog': Scale invariant log error
|
||||
"""
|
||||
thresh = np.maximum((gt / pred), (pred / gt))
|
||||
a1 = (thresh < 1.25).mean()
|
||||
a2 = (thresh < 1.25 ** 2).mean()
|
||||
a3 = (thresh < 1.25 ** 3).mean()
|
||||
|
||||
abs_rel = np.mean(np.abs(gt - pred) / gt)
|
||||
sq_rel = np.mean(((gt - pred) ** 2) / gt)
|
||||
|
||||
rmse = (gt - pred) ** 2
|
||||
rmse = np.sqrt(rmse.mean())
|
||||
|
||||
rmse_log = (np.log(gt) - np.log(pred)) ** 2
|
||||
rmse_log = np.sqrt(rmse_log.mean())
|
||||
|
||||
err = np.log(pred) - np.log(gt)
|
||||
silog = np.sqrt(np.mean(err ** 2) - np.mean(err) ** 2) * 100
|
||||
|
||||
log_10 = (np.abs(np.log10(gt) - np.log10(pred))).mean()
|
||||
return dict(a1=a1, a2=a2, a3=a3, abs_rel=abs_rel, rmse=rmse, log_10=log_10, rmse_log=rmse_log,
|
||||
silog=silog, sq_rel=sq_rel)
|
||||
|
||||
|
||||
def compute_metrics(gt, pred, interpolate=True, garg_crop=False, eigen_crop=True, dataset='nyu', min_depth_eval=0.1, max_depth_eval=10, **kwargs):
|
||||
"""Compute metrics of predicted depth maps. Applies cropping and masking as necessary or specified via arguments. Refer to compute_errors for more details on metrics.
|
||||
"""
|
||||
if 'config' in kwargs:
|
||||
config = kwargs['config']
|
||||
garg_crop = config.garg_crop
|
||||
eigen_crop = config.eigen_crop
|
||||
min_depth_eval = config.min_depth_eval
|
||||
max_depth_eval = config.max_depth_eval
|
||||
|
||||
if gt.shape[-2:] != pred.shape[-2:] and interpolate:
|
||||
pred = nn.functional.interpolate(
|
||||
pred, gt.shape[-2:], mode='bilinear', align_corners=True)
|
||||
|
||||
pred = pred.squeeze().cpu().numpy()
|
||||
pred[pred < min_depth_eval] = min_depth_eval
|
||||
pred[pred > max_depth_eval] = max_depth_eval
|
||||
pred[np.isinf(pred)] = max_depth_eval
|
||||
pred[np.isnan(pred)] = min_depth_eval
|
||||
|
||||
gt_depth = gt.squeeze().cpu().numpy()
|
||||
valid_mask = np.logical_and(
|
||||
gt_depth > min_depth_eval, gt_depth < max_depth_eval)
|
||||
|
||||
if garg_crop or eigen_crop:
|
||||
gt_height, gt_width = gt_depth.shape
|
||||
eval_mask = np.zeros(valid_mask.shape)
|
||||
|
||||
if garg_crop:
|
||||
eval_mask[int(0.40810811 * gt_height):int(0.99189189 * gt_height),
|
||||
int(0.03594771 * gt_width):int(0.96405229 * gt_width)] = 1
|
||||
|
||||
elif eigen_crop:
|
||||
# print("-"*10, " EIGEN CROP ", "-"*10)
|
||||
if dataset == 'kitti':
|
||||
eval_mask[int(0.3324324 * gt_height):int(0.91351351 * gt_height),
|
||||
int(0.0359477 * gt_width):int(0.96405229 * gt_width)] = 1
|
||||
else:
|
||||
# assert gt_depth.shape == (480, 640), "Error: Eigen crop is currently only valid for (480, 640) images"
|
||||
eval_mask[45:471, 41:601] = 1
|
||||
else:
|
||||
eval_mask = np.ones(valid_mask.shape)
|
||||
valid_mask = np.logical_and(valid_mask, eval_mask)
|
||||
return compute_errors(gt_depth[valid_mask], pred[valid_mask])
|
||||
|
||||
|
||||
#################################### Model uilts ################################################
|
||||
|
||||
|
||||
def parallelize(config, model, find_unused_parameters=True):
|
||||
|
||||
if config.gpu is not None:
|
||||
torch.cuda.set_device(config.gpu)
|
||||
model = model.cuda(config.gpu)
|
||||
|
||||
config.multigpu = False
|
||||
if config.distributed:
|
||||
# Use DDP
|
||||
config.multigpu = True
|
||||
config.rank = config.rank * config.ngpus_per_node + config.gpu
|
||||
dist.init_process_group(backend=config.dist_backend, init_method=config.dist_url,
|
||||
world_size=config.world_size, rank=config.rank)
|
||||
config.batch_size = int(config.batch_size / config.ngpus_per_node)
|
||||
# config.batch_size = 8
|
||||
config.workers = int(
|
||||
(config.num_workers + config.ngpus_per_node - 1) / config.ngpus_per_node)
|
||||
print("Device", config.gpu, "Rank", config.rank, "batch size",
|
||||
config.batch_size, "Workers", config.workers)
|
||||
torch.cuda.set_device(config.gpu)
|
||||
model = nn.SyncBatchNorm.convert_sync_batchnorm(model)
|
||||
model = model.cuda(config.gpu)
|
||||
model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[config.gpu], output_device=config.gpu,
|
||||
find_unused_parameters=find_unused_parameters)
|
||||
|
||||
elif config.gpu is None:
|
||||
# Use DP
|
||||
config.multigpu = True
|
||||
model = model.cuda()
|
||||
model = torch.nn.DataParallel(model)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
|
||||
|
||||
class colors:
|
||||
'''Colors class:
|
||||
Reset all colors with colors.reset
|
||||
Two subclasses fg for foreground and bg for background.
|
||||
Use as colors.subclass.colorname.
|
||||
i.e. colors.fg.red or colors.bg.green
|
||||
Also, the generic bold, disable, underline, reverse, strikethrough,
|
||||
and invisible work with the main class
|
||||
i.e. colors.bold
|
||||
'''
|
||||
reset = '\033[0m'
|
||||
bold = '\033[01m'
|
||||
disable = '\033[02m'
|
||||
underline = '\033[04m'
|
||||
reverse = '\033[07m'
|
||||
strikethrough = '\033[09m'
|
||||
invisible = '\033[08m'
|
||||
|
||||
class fg:
|
||||
black = '\033[30m'
|
||||
red = '\033[31m'
|
||||
green = '\033[32m'
|
||||
orange = '\033[33m'
|
||||
blue = '\033[34m'
|
||||
purple = '\033[35m'
|
||||
cyan = '\033[36m'
|
||||
lightgrey = '\033[37m'
|
||||
darkgrey = '\033[90m'
|
||||
lightred = '\033[91m'
|
||||
lightgreen = '\033[92m'
|
||||
yellow = '\033[93m'
|
||||
lightblue = '\033[94m'
|
||||
pink = '\033[95m'
|
||||
lightcyan = '\033[96m'
|
||||
|
||||
class bg:
|
||||
black = '\033[40m'
|
||||
red = '\033[41m'
|
||||
green = '\033[42m'
|
||||
orange = '\033[43m'
|
||||
blue = '\033[44m'
|
||||
purple = '\033[45m'
|
||||
cyan = '\033[46m'
|
||||
lightgrey = '\033[47m'
|
||||
|
||||
|
||||
def printc(text, color):
|
||||
print(f"{color}{text}{colors.reset}")
|
||||
|
||||
############################################
|
||||
|
||||
def get_image_from_url(url):
|
||||
response = requests.get(url)
|
||||
img = Image.open(BytesIO(response.content)).convert("RGB")
|
||||
return img
|
||||
|
||||
def url_to_torch(url, size=(384, 384)):
|
||||
img = get_image_from_url(url)
|
||||
img = img.resize(size, Image.ANTIALIAS)
|
||||
img = torch.from_numpy(np.asarray(img)).float()
|
||||
img = img.permute(2, 0, 1)
|
||||
img.div_(255)
|
||||
return img
|
||||
|
||||
def pil_to_batched_tensor(img):
|
||||
return ToTensor()(img).unsqueeze(0)
|
||||
|
||||
def save_raw_16bit(depth, fpath="raw.png"):
|
||||
if isinstance(depth, torch.Tensor):
|
||||
depth = depth.squeeze().cpu().numpy()
|
||||
|
||||
assert isinstance(depth, np.ndarray), "Depth must be a torch tensor or numpy array"
|
||||
assert depth.ndim == 2, "Depth must be 2D"
|
||||
depth = depth * 256 # scale for 16-bit png
|
||||
depth = depth.astype(np.uint16)
|
||||
depth = Image.fromarray(depth)
|
||||
depth.save(fpath)
|
||||
print("Saved raw depth to", fpath)
|
||||
Reference in New Issue
Block a user