Skip to content

Quick Start

This guide will get you up and running with OrientedDet in minutes.

Basic Geometry Operations

Start with the core geometry primitives:

from oriented_det.geometry import RBox, Polygon, QBox, transforms
from math import radians

# Create a rotated bounding box
rbox = RBox(cx=100, cy=200, width=50, height=30, angle=radians(45))

# Convert to different formats
qbox = transforms.rbox_to_qbox(rbox)
polygon = transforms.rbox_to_polygon(rbox)

# Get properties
print(f"Area: {rbox.area}")
print(f"Aspect ratio: {rbox.aspect_ratio}")
print(f"Corners: {rbox.corners()}")

IoU and NMS

Compute overlap and perform non-maximum suppression:

from oriented_det.geometry import RBox
from oriented_det.ops import iou, nms

boxes = [
    RBox(0, 0, 10, 10, 0),
    RBox(5, 5, 10, 10, 0),
    RBox(100, 100, 10, 10, 0),
]
scores = [0.9, 0.8, 0.6]

overlap = iou.rbox_iou(boxes[0], boxes[1])
keep = nms.oriented_nms(boxes, scores, iou_threshold=0.5)

Loading DOTA Dataset

from oriented_det.data import DOTADataset, build_dota_loader

dataset = DOTADataset(
    root_dir="/path/to/dota",
    split="train",
    difficult_strategy="drop",
)

loader = build_dota_loader(
    root_dir="/path/to/dota",
    split="train",
    batch_size=4,
    shuffle=True,
)

From the repository root after uv pip install -e . (see Installation):

odet train --config configs/oriented_rcnn/dota_le90_1x.json

Or use make train (same default config). Set paths in configs/_base_/datasets/dota_le90.json for your DOTA layout. See Configuration for every JSON field.

Programmatic training (optional)

For custom loops, you can call the training engine directly. Production workflows use JSON configs and odet train:

import torch
from oriented_det import OrientedRCNN
from oriented_det.data import build_dota_loader
from oriented_det.train import train, CheckpointManager
from torch.optim import AdamW

model = OrientedRCNN(backbone_name="resnet50", num_classes=15)
train_loader = build_dota_loader("/path/to/dota", split="train", batch_size=4)
optimizer = AdamW(model.parameters(), lr=1e-4)
checkpoint_manager = CheckpointManager("checkpoints/", best_metric="mAP")
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

train(
    model=model,
    train_loader=train_loader,
    optimizer=optimizer,
    device=device,
    num_epochs=12,
    checkpoint_manager=checkpoint_manager,
    use_amp=True,
)

Inference and evaluation

After training, run validation predictions and offline metrics:

make preds      # writes predictions/<timestamp>/predictions.json
make metrics    # mAP/PR from that JSON
make viewer     # Gradio browser (optional)

For a single demo image:

odet image-demo demo/ runs/<model>/<timestamp>/config.json runs/.../checkpoints/checkpoint_best.pth --out-dir demo/out

Large images use sliding-window inference when resize_mode is fixed or crop (production.overlap_pixels). pad (HRSC2016) always uses one whole-image forward, matching training.

Next Steps