Skip to content

Commit 7c21bba

Browse files
committed
feat: add support of loading dataset metadata
Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp>
1 parent ca9a913 commit 7c21bba

4 files changed

Lines changed: 67 additions & 28 deletions

File tree

docs/tutorials/initialize.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ You can initialize a `Tier4` instance as follows:
2525

2626
>>> from t4_devkit import Tier4
2727

28-
>>> t4 = Tier4("annotation", "data/tier4/", verbose=True)
28+
>>> t4 = Tier4("data/tier4/", verbose=True)
2929
======
3030
Loading T4 tables in `annotation`...
3131
Reverse indexing...

t4_devkit/cli/visualize.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def scene(
4141
) -> None:
4242
_create_dir(output)
4343

44-
t4 = Tier4("annotation", data_root, verbose=False)
44+
t4 = Tier4(data_root, verbose=False)
4545
scene_token = t4.scene[0].token
4646
t4.render_scene(scene_token, future_seconds=future, save_dir=output)
4747

@@ -71,7 +71,7 @@ def instance(
7171
) -> None:
7272
_create_dir(output)
7373

74-
t4 = Tier4("annotation", data_root, verbose=False)
74+
t4 = Tier4(data_root, verbose=False)
7575
t4.render_instance(instance_token=instance, future_seconds=future, save_dir=output)
7676

7777

@@ -99,7 +99,7 @@ def pointcloud(
9999
) -> None:
100100
_create_dir(output)
101101

102-
t4 = Tier4("annotation", data_root, verbose=False)
102+
t4 = Tier4(data_root, verbose=False)
103103
scene_token = t4.scene[0].token
104104
t4.render_pointcloud(
105105
scene_token,

t4_devkit/common/sanity.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
from __future__ import annotations
22

3-
import re
43
import warnings
54
from pathlib import Path
65

76
from attrs import define
87

9-
from t4_devkit import Tier4
8+
from t4_devkit import Tier4, load_metadata
109

1110
__all__ = ["DBException", "sanity_check"]
1211

@@ -30,17 +29,6 @@ def sanity_check(db_root: str | Path, *, include_warning: bool = False) -> DBExc
3029
Returns:
3130
Exception or warning if exits, otherwise returns None.
3231
"""
33-
db_root_path = Path(db_root)
34-
35-
version_pattern = re.compile(r".*/\d+$")
36-
versions = [d.name for d in db_root_path.iterdir() if version_pattern.match(str(d))]
37-
38-
if versions:
39-
version = sorted(versions)[-1]
40-
data_root = db_root_path.joinpath(version).as_posix()
41-
else:
42-
version = None
43-
data_root = db_root_path.as_posix()
4432

4533
with warnings.catch_warnings():
4634
if include_warning:
@@ -49,12 +37,14 @@ def sanity_check(db_root: str | Path, *, include_warning: bool = False) -> DBExc
4937
warnings.filterwarnings("ignore")
5038

5139
try:
52-
_ = Tier4("annotation", data_root=data_root, verbose=False)
40+
_ = Tier4(data_root=db_root, verbose=False)
5341
exception = None
5442
except Exception as e:
43+
metadata = load_metadata(db_root)
44+
5545
exception = DBException(
56-
dataset_id=db_root_path.name,
57-
version=version,
46+
dataset_id=metadata.dataset_id,
47+
version=metadata.version,
5848
message=str(e),
5949
)
6050
return exception

t4_devkit/tier4.py

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
from __future__ import annotations
22

33
import os.path as osp
4+
import re
45
import time
56
import warnings
7+
from pathlib import Path
68
from typing import TYPE_CHECKING, Sequence
79

810
import numpy as np
11+
from attrs import define
912
from pyquaternion import Quaternion
1013

1114
from t4_devkit.common.geometry import is_box_in_image
@@ -38,13 +41,46 @@
3841
Visibility,
3942
)
4043

41-
__all__ = ("Tier4",)
44+
__all__ = ["DBMetadata", "load_metadata", "Tier4"]
45+
46+
47+
@define
48+
class DBMetadata:
49+
data_root: str
50+
dataset_id: str
51+
version: str | None
52+
53+
54+
def load_metadata(db_root: str) -> DBMetadata:
55+
"""Load metadata of T4 dataset including root directory path, dataset ID, and version.
56+
57+
Args:
58+
db_root (str): Path to root directory of database.
59+
60+
Returns:
61+
Metadata of T4 dataset.
62+
"""
63+
db_root_path = Path(db_root)
64+
65+
version_pattern = re.compile(r".*/\d+$")
66+
versions = [d.name for d in db_root_path.iterdir() if version_pattern.match(d.as_posix())]
67+
68+
if versions:
69+
version = sorted(versions)[-1]
70+
data_root = db_root_path.joinpath(version).as_posix()
71+
else:
72+
version = None
73+
data_root = db_root_path.as_posix()
74+
75+
return DBMetadata(data_root=data_root, dataset_id=db_root_path.name, version=version)
4276

4377

4478
class Tier4:
4579
"""Database class for T4 dataset to help query and retrieve information from the database."""
4680

47-
def __init__(self, version: str, data_root: str, verbose: bool = True) -> None:
81+
schema_dir: str = "annotation"
82+
83+
def __init__(self, data_root: str, verbose: bool = True) -> None:
4884
"""Load database and creates reverse indexes and shortcuts.
4985
5086
Args:
@@ -54,7 +90,7 @@ def __init__(self, version: str, data_root: str, verbose: bool = True) -> None:
5490
5591
Examples:
5692
>>> from t4_devkit import Tier4
57-
>>> t4 = Tier4("annotation", "data/tier4")
93+
>>> t4 = Tier4("data/tier4")
5894
======
5995
Loading T4 tables in `annotation`...
6096
Reverse indexing...
@@ -80,16 +116,14 @@ def __init__(self, version: str, data_root: str, verbose: bool = True) -> None:
80116
======
81117
82118
"""
83-
self.version = version
84-
self.data_root = data_root
85-
self.verbose = verbose
119+
self._metadata = load_metadata(data_root)
86120

87121
if not osp.exists(self.data_root):
88122
raise FileNotFoundError(f"Database directory is not found: {self.data_root}")
89123

90124
start_time = time.time()
91125
if verbose:
92-
print(f"======\nLoading T4 tables in `{self.version}`...")
126+
print(f"======\nLoading T4 tables in `{self.schema_dir}`...")
93127

94128
# assign tables explicitly
95129
self.attribute: list[Attribute] = self.__load_table__(SchemaName.ATTRIBUTE)
@@ -127,6 +161,21 @@ def __init__(self, version: str, data_root: str, verbose: bool = True) -> None:
127161
self._timeseries_helper = TimeseriesHelper(self)
128162
self._rendering_helper = RenderingHelper(self)
129163

164+
@property
165+
def data_root(self) -> str:
166+
"""Return the path to dataset root directory."""
167+
return self._metadata.data_root
168+
169+
@property
170+
def dataset_id(self) -> str:
171+
"""Return the dataset ID."""
172+
return self._metadata.dataset_id
173+
174+
@property
175+
def version(self) -> str | None:
176+
"""Return the dataset version, or None if it is failed to lookup."""
177+
return self._metadata.version
178+
130179
def __load_table__(self, schema: SchemaName) -> list[SchemaTable]:
131180
"""Load schema table from a json file.
132181
@@ -139,7 +188,7 @@ def __load_table__(self, schema: SchemaName) -> list[SchemaTable]:
139188
Returns:
140189
Loaded table data saved in `.json`.
141190
"""
142-
filepath = osp.join(self.data_root, self.version, schema.filename)
191+
filepath = osp.join(self.data_root, self.schema_dir, schema.filename)
143192
if not osp.exists(filepath) and schema.is_optional():
144193
return []
145194

0 commit comments

Comments
 (0)