oriented-det 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- export/__init__.py +9 -0
- export/ort_runtime.py +67 -0
- export/postprocess.py +151 -0
- export/scripts/__init__.py +6 -0
- export/scripts/build_faster_rcnn_savedmodel.py +104 -0
- export/scripts/export_onnx.py +210 -0
- export/scripts/onnx_to_savedmodel.py +35 -0
- export/scripts/predict_savedmodel.py +94 -0
- export/scripts/save_predictions_tf.py +447 -0
- export/scripts/to_tflite.py +32 -0
- export/tests/test_export_onnx_optional.py +82 -0
- export/tests/test_export_wrappers.py +105 -0
- export/tests/test_faster_rcnn_export_parity.py +201 -0
- export/tests/test_ort_runtime.py +41 -0
- export/tf_serving_model.py +96 -0
- export/val_dataset.py +116 -0
- export/wrappers.py +161 -0
- oriented_det/__init__.py +77 -0
- oriented_det/cli/__init__.py +92 -0
- oriented_det/cli/train.py +18 -0
- oriented_det/configs/_base_/augmentation.json +21 -0
- oriented_det/configs/_base_/datasets/dota_le90.json +21 -0
- oriented_det/configs/_base_/fp16.json +5 -0
- oriented_det/configs/_base_/models/oriented_rcnn_r50.json +26 -0
- oriented_det/configs/_base_/models/rotated_faster_rcnn_r50.json +53 -0
- oriented_det/configs/_base_/models/rotated_retinanet_r50.json +30 -0
- oriented_det/configs/_base_/preprocessing.json +8 -0
- oriented_det/configs/_base_/schedules/1x.json +33 -0
- oriented_det/configs/config.schema.json +404 -0
- oriented_det/configs/oriented_rcnn/dota_le90_1x.json +121 -0
- oriented_det/configs/oriented_rcnn/dota_le90_3x.json +11 -0
- oriented_det/configs/rotated_faster_rcnn/dota_le90_1x.json +119 -0
- oriented_det/configs/rotated_faster_rcnn/dota_le90_3x.json +9 -0
- oriented_det/configs/rotated_retinanet/dota_le90_1x.json +107 -0
- oriented_det/configs/rotated_retinanet/dota_le90_3x.json +30 -0
- oriented_det/data/__init__.py +89 -0
- oriented_det/data/airbus_playground.py +611 -0
- oriented_det/data/dota.py +741 -0
- oriented_det/data/dota_classes.py +26 -0
- oriented_det/data/evaluation.py +648 -0
- oriented_det/data/flips.py +115 -0
- oriented_det/data/preprocessing.py +335 -0
- oriented_det/data/tiling.py +399 -0
- oriented_det/data/transforms.py +377 -0
- oriented_det/geometry/__init__.py +8 -0
- oriented_det/geometry/poly.py +127 -0
- oriented_det/geometry/qbox.py +63 -0
- oriented_det/geometry/rbox.py +250 -0
- oriented_det/geometry/transforms.py +266 -0
- oriented_det/models/__init__.py +36 -0
- oriented_det/models/backbones/__init__.py +11 -0
- oriented_det/models/backbones/resnet_fpn.py +79 -0
- oriented_det/models/backbones/utils.py +81 -0
- oriented_det/models/bbox_coder.py +355 -0
- oriented_det/models/faster_rcnn_inference.py +494 -0
- oriented_det/models/horizontal_roi_coder.py +155 -0
- oriented_det/models/oriented_rcnn.py +1256 -0
- oriented_det/models/oriented_roi.py +1664 -0
- oriented_det/models/oriented_rpn.py +2104 -0
- oriented_det/models/rotated_retinanet.py +1030 -0
- oriented_det/models/utils.py +590 -0
- oriented_det/ops/__init__.py +58 -0
- oriented_det/ops/gpu_ops.py +1109 -0
- oriented_det/ops/iou.py +172 -0
- oriented_det/ops/kfiou.py +275 -0
- oriented_det/ops/nms.py +202 -0
- oriented_det/ops/probiou.py +165 -0
- oriented_det/ops/rotated_ops.py +122 -0
- oriented_det/ops/utils.py +257 -0
- oriented_det/pretrained/__init__.py +23 -0
- oriented_det/pretrained/hub.py +249 -0
- oriented_det/pretrained/manifest.json +46 -0
- oriented_det/runtime/__init__.py +29 -0
- oriented_det/runtime/checkpoint.py +274 -0
- oriented_det/runtime/collate.py +348 -0
- oriented_det/runtime/inference.py +1286 -0
- oriented_det/train/__init__.py +102 -0
- oriented_det/train/config.py +872 -0
- oriented_det/train/engine.py +2933 -0
- oriented_det/train/grouped_ce.py +139 -0
- oriented_det/train/piecewise_schedule.py +33 -0
- oriented_det/train/profiler.py +287 -0
- oriented_det/train/utils.py +999 -0
- oriented_det/utils/__init__.py +31 -0
- oriented_det/utils/config.py +376 -0
- oriented_det/utils/device.py +35 -0
- oriented_det/utils/logging.py +163 -0
- oriented_det/utils/progress.py +62 -0
- oriented_det/utils/viz.py +181 -0
- oriented_det-0.1.0.dist-info/METADATA +313 -0
- oriented_det-0.1.0.dist-info/RECORD +115 -0
- oriented_det-0.1.0.dist-info/WHEEL +5 -0
- oriented_det-0.1.0.dist-info/entry_points.txt +2 -0
- oriented_det-0.1.0.dist-info/licenses/LICENSE +202 -0
- oriented_det-0.1.0.dist-info/top_level.txt +3 -0
- tools/__init__.py +1 -0
- tools/app.py +1284 -0
- tools/dataset_stats.py +389 -0
- tools/dota_labels_to_comma.py +132 -0
- tools/free_gpu.py +142 -0
- tools/generate_airbus_playground_csv.py +154 -0
- tools/image_demo.py +200 -0
- tools/lr_finder.py +771 -0
- tools/measure_sampled_riou_error.py +483 -0
- tools/playground_to_dota.py +290 -0
- tools/pretrained_download.py +49 -0
- tools/preview_augmentation.py +510 -0
- tools/publish_checkpoint.py +96 -0
- tools/save_predictions.py +2350 -0
- tools/sync_vendored_configs.py +94 -0
- tools/tile_dota.py +447 -0
- tools/train.py +2324 -0
- tools/train_example.py +244 -0
- tools/train_multi_gpu.py +367 -0
- tools/visualize_boxes.py +183 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Export Airbus Playground folder layout to DOTA-format directories (images + labels).
|
|
3
|
+
|
|
4
|
+
Reads from the Playground export structure (dataset_id/samples/..., dataset_id/labels/...),
|
|
5
|
+
converts polygon annotations to DOTA OBB format (8 coords + class + difficulty), and writes
|
|
6
|
+
images and .txt label files. Optionally splits output into train/val by group ratio, or via an
|
|
7
|
+
existing split CSV from ``generate_airbus_playground_csv.py`` (integer fold ids or legacy train/val).
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
# Single output dir (no split)
|
|
11
|
+
python tools/playground_to_dota.py --data-root /path/to/playground_export --output-dir /path/to/dota_out
|
|
12
|
+
|
|
13
|
+
# Train/val split by image group (ratio; independent of generate_airbus_playground_csv folds)
|
|
14
|
+
python tools/playground_to_dota.py --data-root /path/to/export --output-dir /path/to/dota_out --val-ratio 0.2 --seed 42
|
|
15
|
+
|
|
16
|
+
# Use existing split CSV (integer fold ids; val fold 0 by default, or pass --val-split-id)
|
|
17
|
+
python tools/playground_to_dota.py --data-root /path/to/export --output-dir /path/to/dota_out --split-file /path/to/export/split.csv
|
|
18
|
+
|
|
19
|
+
# Label filtering and mapping
|
|
20
|
+
python tools/playground_to_dota.py --data-root /path/to/export --output-dir /path/to/dota_out --ignore-label Confuser --map-label "taxi=car"
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import argparse
|
|
26
|
+
import csv
|
|
27
|
+
import random
|
|
28
|
+
import shutil
|
|
29
|
+
import sys
|
|
30
|
+
from collections import defaultdict
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
from typing import Dict, List, Optional, Set, Tuple
|
|
33
|
+
|
|
34
|
+
# Ensure oriented_det is importable when run as script
|
|
35
|
+
_REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
36
|
+
if str(_REPO_ROOT) not in sys.path:
|
|
37
|
+
sys.path.insert(0, str(_REPO_ROOT))
|
|
38
|
+
|
|
39
|
+
from oriented_det.data import format_dota_line
|
|
40
|
+
from oriented_det.data.airbus_playground import (
|
|
41
|
+
TileRecord,
|
|
42
|
+
discover_airbus_tiles,
|
|
43
|
+
detect_airbus_split_csv_format,
|
|
44
|
+
_load_airbus_label_rows,
|
|
45
|
+
_image_group_key,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _unique_tile_basename(tile: TileRecord) -> str:
|
|
50
|
+
"""Return a unique basename for the tile (no extension) to avoid collisions across zones."""
|
|
51
|
+
return f"{tile.dataset_id}_{tile.zone_id}_{tile.image_id}_{tile.tile_id}"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _compute_split_by_ratio(
|
|
55
|
+
tiles: List[TileRecord],
|
|
56
|
+
val_ratio: float,
|
|
57
|
+
seed: int,
|
|
58
|
+
) -> Set[Tuple[str, str, str]]:
|
|
59
|
+
"""Compute which (dataset_id, zone_id, image_id) groups are validation from a ratio."""
|
|
60
|
+
groups: Dict[Tuple[str, str, str], List[TileRecord]] = defaultdict(list)
|
|
61
|
+
for tile in tiles:
|
|
62
|
+
groups[_image_group_key(tile)].append(tile)
|
|
63
|
+
group_keys = sorted(groups.keys())
|
|
64
|
+
rng = random.Random(seed)
|
|
65
|
+
rng.shuffle(group_keys)
|
|
66
|
+
n_val = max(1, int(round(len(group_keys) * val_ratio)))
|
|
67
|
+
return set(group_keys[:n_val])
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _load_split_file(split_path: Path, *, val_split_id: int = 0) -> Dict[str, str]:
|
|
71
|
+
"""Load split CSV: tile_relpath -> 'train' | 'val'.
|
|
72
|
+
|
|
73
|
+
Supports legacy ``train`` / ``val`` strings or integer fold ids (same convention as
|
|
74
|
+
``generate_airbus_playground_csvs``); for fold ids, tiles whose fold equals ``val_split_id``
|
|
75
|
+
are mapped to ``val``.
|
|
76
|
+
"""
|
|
77
|
+
with split_path.open("r", encoding="utf-8", newline="") as f:
|
|
78
|
+
reader = csv.DictReader(f)
|
|
79
|
+
raw_rows = list(reader)
|
|
80
|
+
if not raw_rows:
|
|
81
|
+
return {}
|
|
82
|
+
mode = detect_airbus_split_csv_format([r.get("split", "") for r in raw_rows])
|
|
83
|
+
out: Dict[str, str] = {}
|
|
84
|
+
for row in raw_rows:
|
|
85
|
+
rel = (row.get("tile_relpath") or "").strip()
|
|
86
|
+
if not rel:
|
|
87
|
+
continue
|
|
88
|
+
split_raw = row.get("split") or ""
|
|
89
|
+
if mode == "train_val":
|
|
90
|
+
sv = split_raw.strip().lower()
|
|
91
|
+
if sv in ("train", "val"):
|
|
92
|
+
out[rel] = sv
|
|
93
|
+
else:
|
|
94
|
+
try:
|
|
95
|
+
sid = int(str(split_raw).strip())
|
|
96
|
+
except ValueError:
|
|
97
|
+
continue
|
|
98
|
+
out[rel] = "val" if sid == val_split_id else "train"
|
|
99
|
+
return out
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def run(
|
|
103
|
+
data_root: Path,
|
|
104
|
+
output_dir: Path,
|
|
105
|
+
*,
|
|
106
|
+
val_ratio: Optional[float] = None,
|
|
107
|
+
seed: int = 42,
|
|
108
|
+
split_file: Optional[Path] = None,
|
|
109
|
+
val_split_id: int = 0,
|
|
110
|
+
ignore_labels: Optional[List[str]] = None,
|
|
111
|
+
map_labels: Optional[Dict[str, str]] = None,
|
|
112
|
+
dry_run: bool = False,
|
|
113
|
+
) -> Dict[str, int]:
|
|
114
|
+
"""Export Playground export to DOTA dirs. Returns stats dict (tiles_written, train_count, val_count, objects_total, objects_skipped)."""
|
|
115
|
+
root = Path(data_root).resolve()
|
|
116
|
+
out = Path(output_dir).resolve()
|
|
117
|
+
|
|
118
|
+
if not root.is_dir():
|
|
119
|
+
raise FileNotFoundError(f"Data root is not a directory: {root}")
|
|
120
|
+
|
|
121
|
+
tiles = discover_airbus_tiles(root)
|
|
122
|
+
if not tiles:
|
|
123
|
+
raise FileNotFoundError(f"No Airbus Playground tiles found under {root}")
|
|
124
|
+
|
|
125
|
+
# Resolve train/val assignment
|
|
126
|
+
use_split_dirs = False
|
|
127
|
+
val_keys: Optional[Set[Tuple[str, str, str]]] = None
|
|
128
|
+
split_by_tile: Optional[Dict[str, str]] = None
|
|
129
|
+
|
|
130
|
+
if split_file is not None:
|
|
131
|
+
if not split_file.exists():
|
|
132
|
+
raise FileNotFoundError(f"Split file not found: {split_file}")
|
|
133
|
+
split_by_tile = _load_split_file(split_file, val_split_id=val_split_id)
|
|
134
|
+
if not split_by_tile:
|
|
135
|
+
raise ValueError("Split file has no valid tile_relpath -> split rows.")
|
|
136
|
+
use_split_dirs = True
|
|
137
|
+
elif val_ratio is not None:
|
|
138
|
+
if not (0.0 < val_ratio < 1.0):
|
|
139
|
+
raise ValueError("val_ratio must be in (0, 1).")
|
|
140
|
+
val_keys = _compute_split_by_ratio(tiles, val_ratio, seed)
|
|
141
|
+
use_split_dirs = True
|
|
142
|
+
|
|
143
|
+
ignore_set: Optional[Set[str]] = None
|
|
144
|
+
if ignore_labels:
|
|
145
|
+
ignore_set = set(ignore_labels)
|
|
146
|
+
map_dict = dict(map_labels or {})
|
|
147
|
+
|
|
148
|
+
# Output layout: [output_dir/] [train|val/] images/, labels/
|
|
149
|
+
def out_paths(tile: TileRecord, split: str) -> Tuple[Path, Path]:
|
|
150
|
+
base = _unique_tile_basename(tile)
|
|
151
|
+
if use_split_dirs:
|
|
152
|
+
img_dir = out / split / "images"
|
|
153
|
+
lbl_dir = out / split / "labels"
|
|
154
|
+
else:
|
|
155
|
+
img_dir = out / "images"
|
|
156
|
+
lbl_dir = out / "labels"
|
|
157
|
+
return img_dir / f"{base}.jpg", lbl_dir / f"{base}.txt"
|
|
158
|
+
|
|
159
|
+
def get_split(tile: TileRecord) -> str:
|
|
160
|
+
if split_by_tile is not None:
|
|
161
|
+
return split_by_tile.get(tile.tile_relpath, "train")
|
|
162
|
+
if val_keys is not None:
|
|
163
|
+
return "val" if _image_group_key(tile) in val_keys else "train"
|
|
164
|
+
return "train"
|
|
165
|
+
|
|
166
|
+
stats = {
|
|
167
|
+
"tiles_total": len(tiles),
|
|
168
|
+
"tiles_skipped": 0,
|
|
169
|
+
"tiles_written": 0,
|
|
170
|
+
"train_tiles": 0,
|
|
171
|
+
"val_tiles": 0,
|
|
172
|
+
"objects_total": 0,
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
for tile in sorted(tiles, key=lambda t: t.tile_relpath):
|
|
176
|
+
img_src = root / tile.tile_relpath
|
|
177
|
+
if not img_src.exists():
|
|
178
|
+
stats["tiles_skipped"] += 1
|
|
179
|
+
if not dry_run:
|
|
180
|
+
print(f"Warning: image not found {img_src}", file=sys.stderr)
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
split = get_split(tile)
|
|
184
|
+
img_dst, lbl_dst = out_paths(tile, split)
|
|
185
|
+
|
|
186
|
+
rows = _load_airbus_label_rows(
|
|
187
|
+
root / tile.label_relpath,
|
|
188
|
+
ignore_labels=ignore_set,
|
|
189
|
+
map_labels=map_dict if map_dict else None,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
if not dry_run:
|
|
193
|
+
img_dst.parent.mkdir(parents=True, exist_ok=True)
|
|
194
|
+
lbl_dst.parent.mkdir(parents=True, exist_ok=True)
|
|
195
|
+
shutil.copy2(img_src, img_dst)
|
|
196
|
+
# Official DOTA format: comma-separated (x1, y1, x2, y2, x3, y3, x4, y4, category, difficult)
|
|
197
|
+
lines = []
|
|
198
|
+
for dota_coords, class_name, difficult in rows:
|
|
199
|
+
coords = [float(x) for x in dota_coords.split()]
|
|
200
|
+
lines.append(format_dota_line(*coords, class_name, difficult))
|
|
201
|
+
lbl_dst.write_text("\n".join(lines), encoding="utf-8")
|
|
202
|
+
|
|
203
|
+
stats["tiles_written"] += 1
|
|
204
|
+
stats["objects_total"] += len(rows)
|
|
205
|
+
if split == "train":
|
|
206
|
+
stats["train_tiles"] += 1
|
|
207
|
+
else:
|
|
208
|
+
stats["val_tiles"] += 1
|
|
209
|
+
|
|
210
|
+
return stats
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def main() -> int:
|
|
214
|
+
parser = argparse.ArgumentParser(
|
|
215
|
+
description="Export Airbus Playground export to DOTA-format directories (images + .txt labels).",
|
|
216
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
217
|
+
)
|
|
218
|
+
parser.add_argument("--data-root", type=Path, required=True, help="Root of Playground export (dataset_id/samples/..., labels/...).")
|
|
219
|
+
parser.add_argument("--output-dir", type=Path, required=True, help="Output root for DOTA dirs (images/ and labels/, or train/val subdirs).")
|
|
220
|
+
parser.add_argument(
|
|
221
|
+
"--val-ratio",
|
|
222
|
+
type=float,
|
|
223
|
+
default=None,
|
|
224
|
+
help="Validation ratio by image group (0–1). If set, creates output_dir/train and output_dir/val.",
|
|
225
|
+
)
|
|
226
|
+
parser.add_argument("--seed", type=int, default=42, help="Random seed when using --val-ratio.")
|
|
227
|
+
parser.add_argument(
|
|
228
|
+
"--split-file",
|
|
229
|
+
type=Path,
|
|
230
|
+
default=None,
|
|
231
|
+
help="Path to split CSV (tile_relpath, split). Overrides --val-ratio. Integer split column uses --val-split-id as the val fold.",
|
|
232
|
+
)
|
|
233
|
+
parser.add_argument(
|
|
234
|
+
"--val-split-id",
|
|
235
|
+
type=int,
|
|
236
|
+
default=0,
|
|
237
|
+
help="When --split-file has integer fold ids, treat this fold as validation (default 0).",
|
|
238
|
+
)
|
|
239
|
+
parser.add_argument("--ignore-label", action="append", default=[], dest="ignore_labels", help="Label to ignore (repeatable).")
|
|
240
|
+
parser.add_argument(
|
|
241
|
+
"--map-label",
|
|
242
|
+
action="append",
|
|
243
|
+
default=[],
|
|
244
|
+
dest="map_label_list",
|
|
245
|
+
help="Mapping as src=dst (repeatable). Example: taxi=car",
|
|
246
|
+
)
|
|
247
|
+
parser.add_argument("--dry-run", action="store_true", help="Do not write files; only report stats.")
|
|
248
|
+
args = parser.parse_args()
|
|
249
|
+
|
|
250
|
+
map_labels: Dict[str, str] = {}
|
|
251
|
+
for entry in args.map_label_list:
|
|
252
|
+
if "=" not in entry:
|
|
253
|
+
print(f"Error: invalid --map-label '{entry}'. Use src=dst.", file=sys.stderr)
|
|
254
|
+
return 1
|
|
255
|
+
src, dst = entry.split("=", 1)
|
|
256
|
+
src, dst = src.strip(), dst.strip()
|
|
257
|
+
if not src or not dst:
|
|
258
|
+
print(f"Error: empty src or dst in --map-label '{entry}'.", file=sys.stderr)
|
|
259
|
+
return 1
|
|
260
|
+
map_labels[src] = dst
|
|
261
|
+
|
|
262
|
+
try:
|
|
263
|
+
stats = run(
|
|
264
|
+
args.data_root,
|
|
265
|
+
args.output_dir,
|
|
266
|
+
val_ratio=args.val_ratio,
|
|
267
|
+
seed=args.seed,
|
|
268
|
+
split_file=args.split_file,
|
|
269
|
+
val_split_id=args.val_split_id,
|
|
270
|
+
ignore_labels=args.ignore_labels or None,
|
|
271
|
+
map_labels=map_labels if map_labels else None,
|
|
272
|
+
dry_run=args.dry_run,
|
|
273
|
+
)
|
|
274
|
+
except (FileNotFoundError, ValueError) as e:
|
|
275
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
276
|
+
return 1
|
|
277
|
+
|
|
278
|
+
print("Playground → DOTA export " + ("(dry run)" if args.dry_run else "complete."))
|
|
279
|
+
print(f" Tiles total: {stats['tiles_total']}")
|
|
280
|
+
print(f" Tiles skipped: {stats['tiles_skipped']}")
|
|
281
|
+
print(f" Tiles written: {stats['tiles_written']}")
|
|
282
|
+
if stats["train_tiles"] or stats["val_tiles"]:
|
|
283
|
+
print(f" Train tiles: {stats['train_tiles']}")
|
|
284
|
+
print(f" Val tiles: {stats['val_tiles']}")
|
|
285
|
+
print(f" Objects total: {stats['objects_total']}")
|
|
286
|
+
return 0
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
if __name__ == "__main__":
|
|
290
|
+
sys.exit(main())
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Download OrientedDet pretrained checkpoints from Hugging Face Hub."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main() -> None:
|
|
11
|
+
parser = argparse.ArgumentParser(
|
|
12
|
+
description="Download OrientedDet pretrained checkpoints from Hugging Face Hub."
|
|
13
|
+
)
|
|
14
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
15
|
+
|
|
16
|
+
dl = sub.add_parser("download", help="Download one or more registered checkpoints")
|
|
17
|
+
dl.add_argument(
|
|
18
|
+
"assets",
|
|
19
|
+
nargs="+",
|
|
20
|
+
help="Asset name or .pth filename (see `list`)",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
sub.add_parser("list", help="List registered pretrained assets")
|
|
24
|
+
|
|
25
|
+
args = parser.parse_args()
|
|
26
|
+
|
|
27
|
+
from oriented_det.pretrained import download_asset, list_assets, load_manifest
|
|
28
|
+
|
|
29
|
+
if args.command == "list":
|
|
30
|
+
manifest = load_manifest()
|
|
31
|
+
repo_id = manifest.get("repo_id", "")
|
|
32
|
+
print(f"repo_id: {repo_id}")
|
|
33
|
+
print(f"revision: {manifest.get('revision', 'main')}")
|
|
34
|
+
print("assets:")
|
|
35
|
+
for name, remote in sorted(list_assets().items()):
|
|
36
|
+
print(f" {name} -> {remote}")
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
for asset in args.assets:
|
|
40
|
+
path = download_asset(asset)
|
|
41
|
+
print(f"Downloaded {asset} -> {path}")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if __name__ == "__main__":
|
|
45
|
+
try:
|
|
46
|
+
main()
|
|
47
|
+
except (ImportError, KeyError, RuntimeError, ValueError) as e:
|
|
48
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
49
|
+
raise SystemExit(1) from e
|