Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,32 @@ python tools/install.py --editable
python -m autoptz
```

- `requirements/base.txt` — full stack: ONNX Runtime, OpenCV, PySide6, PyAV,
ultralytics, boxmot, insightface, PTZ libs, plus OS-specific camera helpers
through pip environment markers.
The default `python tools/install.py` is **torch-free** (~2–3 GB lighter):
detection runs on ONNX Runtime, multi-object tracking uses the built-in
lightweight IoU tracker, and detector/pose weights provision via the
prebuilt-ONNX download. The two PyTorch-heavy fallbacks are opt-in extras:

```bash
python tools/install.py --editable # lean, torch-free default
python tools/install.py --full --editable # + tracking + export extras
python tools/install.py --with-tracking --editable # boxmot only
python tools/install.py --with-export --editable # ultralytics only
```

- **tracking** (`requirements/tracking.txt`, `boxmot`) — occlusion-robust
BoT-SORT/DeepOCSORT/ByteTrack trackers and the OSNet ReID backend used for
body-appearance recovery after occlusion.
- **export** (`requirements/export.txt`, `ultralytics`) — the YOLO11 `.pt` →
ONNX export fallback, used only when the prebuilt ONNX download is unreachable.

- `requirements/base.txt` — torch-free core: ONNX Runtime, OpenCV, PySide6,
PyAV, insightface, PTZ libs, plus OS-specific camera helpers through pip
environment markers.
- `requirements/tracking.txt` / `requirements/export.txt` — optional torch
extras (above); `--dev` and CI install both automatically (the test suite
needs them).
- `requirements/ui.txt` — UI-only (no ML stack), for quick UI work.
- `requirements/dev.txt` — pytest, ruff, mypy.
- `requirements/dev.txt` — pytest, ruff, mypy (plus the tracking + export extras).
- `tools/install.py` — one readable install entry point that selects the right
profile and prevents multiple `onnxruntime*` wheels from coexisting.

Expand Down
21 changes: 19 additions & 2 deletions requirements/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,31 @@ normal pip environment markers for OS-specific packages such as macOS
AVFoundation support. GPU selection needs `tools/install.py` or an explicit
accelerator file because pip requirements cannot inspect your GPU hardware.

The **default install is torch-free** (~2–3 GB lighter): detection runs on ONNX
Runtime, multi-object tracking uses the built-in lightweight IoU tracker, and
detector/pose weights provision via the prebuilt-ONNX download. The two
torch-heavy fallbacks are opt-in extras:

```bash
python tools/install.py --editable # lean, torch-free default
python tools/install.py --full --editable # + tracking + export extras
python tools/install.py --with-tracking --editable # + boxmot tracking only
python tools/install.py --with-export --editable # + ultralytics export only
```

`--dev` (and CI) install both extras automatically because the test suite needs
them — `dev.txt` references `tracking.txt` and `export.txt`.

| File | When to install |
| --- | --- |
| `base.txt` | Always — full app: inference, tracking, PTZ, UI. Ships CPU ONNX Runtime (+ CoreML on macOS) and OS-specific camera helpers via markers. |
| `base.txt` | Always — torch-free core: ONNX inference, IoU tracking, PTZ, UI. Ships CPU ONNX Runtime (+ CoreML on macOS) and OS-specific camera helpers via markers. |
| `requirements.txt` | Compatibility entry point for tools that expect the conventional filename, including GitHub Dependency Graph. Includes `base.txt`. |
| `tracking.txt` | Optional extra — `boxmot` adds BoT-SORT/DeepOCSORT/ByteTrack + OSNet ReID for occlusion-robust tracking. Pulls in PyTorch. `--with-tracking` / `--full`. |
| `export.txt` | Optional extra — `ultralytics` adds the YOLO11 `.pt` → ONNX export fallback (used only when the prebuilt download is unreachable). Pulls in PyTorch. `--with-export` / `--full`. |
| `gpu-nvidia.txt` | NVIDIA GPU (Windows/Linux) — TensorRT + CUDA. Replaces the CPU `onnxruntime`. |
| `gpu-directml.txt` | AMD/Intel GPU on Windows — DirectML. Replaces the CPU `onnxruntime`. |
| `openvino.txt` | Intel CPU/iGPU (any OS) — OpenVINO. Replaces the CPU `onnxruntime`. |
| `dev.txt` | Contributors — ruff, mypy, pytest. |
| `dev.txt` | Contributors — ruff, mypy, pytest. Also pulls in `tracking.txt` + `export.txt` (the test suite needs them). |
| `packaging.txt` | Building installers — PyInstaller (see [docs/building.md](../docs/building.md)). |
| `ui.txt` | UI-only iteration — minimal, no ML stack. |

Expand Down
20 changes: 8 additions & 12 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,14 @@ onnx==1.21.0
# AUTOPTZ_MODEL_PATH). The UI uses cached models unless the user explicitly
# enables automatic downloads in Engine > Models.
#
# Ultralytics is an OPTIONAL *fallback* used only when the prebuilt download is
# unreachable; it exports the YOLO11 .pt → ONNX but pulls in torch (heavy). Omit
# it on minimal installs — detection still works via the prebuilt download, and
# the engine degrades to live-preview-only only if BOTH paths fail.
ultralytics>=8.3.0

# BoxMOT: multi-object tracker collection (BoT-SORT, DeepOCSORT, ByteTrack).
# Also provides the OSNet ReID backend used by engine/pipeline/reid.py for
# body-appearance recovery after occlusion (weights auto-download on first use).
# Optional at import time — Tracker / BodyReID degrade gracefully if absent.
# Pin to a specific release once a stable wheel is available for all platforms.
boxmot>=10.0.91
# The default install is torch-free: detection runs on ONNX Runtime, tracking
# falls back to the built-in IoU tracker, and weights provision via the prebuilt
# ONNX download. The two torch-heavy fallbacks live in OPTIONAL extras (omit them
# on a default install):
# requirements/tracking.txt — boxmot (BoT-SORT/DeepOCSORT/ByteTrack + OSNet ReID)
# requirements/export.txt — ultralytics (YOLO11 .pt → ONNX export fallback)
# Install both with `python tools/install.py --full` (or --with-tracking /
# --with-export). `--dev` and CI pull them in automatically via dev.txt.

# ── face identity ───────────────────────────────────────────────────
# InsightFace: SCRFD face detector + ArcFace 512-d embeddings (engine/pipeline/
Expand Down
6 changes: 6 additions & 0 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
# Install after base:
# python tools/install.py --dev --editable

# The test suite needs the torch-heavy tracking + export extras (tracker tests
# and model-export tests import boxmot / ultralytics), so contributors and CI
# always get them even though the default end-user install stays torch-free.
-r tracking.txt
-r export.txt

# ── testing ───────────────────────────────────────────────────────────────────
pytest==9.0.3
pytest-timeout==2.3.1
Expand Down
15 changes: 15 additions & 0 deletions requirements/export.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# AutoPTZ — optional export extra (heavy: pulls in PyTorch via ultralytics)
# Install:
# python tools/install.py --with-export # or --full
# pip install -r requirements/export.txt
#
# The DEFAULT install is torch-free: ModelManager provisions detector/pose
# weights via the prebuilt-ONNX download (engine/runtime/models.py). This extra
# adds the YOLO11 .pt → ONNX export fallback used only when that download is
# unreachable.

# Ultralytics is an OPTIONAL *fallback* used only when the prebuilt download is
# unreachable; it exports the YOLO11 .pt → ONNX but pulls in torch (heavy). Omit
# it on minimal installs — detection still works via the prebuilt download, and
# the engine degrades to live-preview-only only if BOTH paths fail.
ultralytics>=8.3.0
16 changes: 16 additions & 0 deletions requirements/tracking.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# AutoPTZ — optional tracking extra (heavy: pulls in PyTorch via boxmot)
# Install:
# python tools/install.py --with-tracking # or --full
# pip install -r requirements/tracking.txt
#
# The DEFAULT install is torch-free: detection runs on ONNX Runtime and tracking
# falls back to the built-in lightweight IoU tracker (engine/pipeline/track.py).
# This extra adds the occlusion-robust BoT-SORT/DeepOCSORT/ByteTrack trackers and
# the OSNet ReID backend.

# BoxMOT: multi-object tracker collection (BoT-SORT, DeepOCSORT, ByteTrack).
# Also provides the OSNet ReID backend used by engine/pipeline/reid.py for
# body-appearance recovery after occlusion (weights auto-download on first use).
# Optional at import time — Tracker / BodyReID degrade gracefully if absent.
# Pin to a specific release once a stable wheel is available for all platforms.
boxmot>=10.0.91
77 changes: 77 additions & 0 deletions tests/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,83 @@ def test_ci_install_is_hardware_independent() -> None:
assert any("hardware-independent" in note for note in plan.notes)


# ---------------------------------------------------------------------------
# Torch-free default + opt-in extras
# ---------------------------------------------------------------------------


def test_default_install_is_torch_free() -> None:
"""The bare default plan must NOT include the torch-heavy extras."""
system = SystemInfo("Darwin", "arm64", ("Apple M3",))

plan = plan_install(system)

assert "tracking" not in plan.profiles
assert "export" not in plan.profiles
args = [step.args for step in plan.steps]
assert ("install", "-r", "requirements/tracking.txt") not in args
assert ("install", "-r", "requirements/export.txt") not in args
assert any("torch-free" in note for note in plan.notes)


def test_dev_install_pulls_extras_via_dev_txt() -> None:
"""--dev installs dev.txt, which references tracking.txt + export.txt, so the
extras are NOT added as separate steps (avoids redundant pip work)."""
system = SystemInfo("Linux", "x86_64", ())

plan = plan_install(system, dev=True)

args = [step.args for step in plan.steps]
assert ("install", "-r", "requirements/dev.txt") in args
# dev.txt's `-r tracking.txt` / `-r export.txt` cover these, so install.py
# must not duplicate them.
assert ("install", "-r", "requirements/tracking.txt") not in args
assert ("install", "-r", "requirements/export.txt") not in args


def test_full_install_adds_both_extras() -> None:
system = SystemInfo("Linux", "x86_64", ())

plan = plan_install(system, full=True)

assert plan.profiles == ("base", "tracking", "export")
args = [step.args for step in plan.steps]
assert ("install", "-r", "requirements/tracking.txt") in args
assert ("install", "-r", "requirements/export.txt") in args


def test_with_tracking_adds_only_tracking() -> None:
system = SystemInfo("Linux", "x86_64", ())

plan = plan_install(system, with_tracking=True)

args = [step.args for step in plan.steps]
assert ("install", "-r", "requirements/tracking.txt") in args
assert ("install", "-r", "requirements/export.txt") not in args


def test_with_export_adds_only_export() -> None:
system = SystemInfo("Linux", "x86_64", ())

plan = plan_install(system, with_export=True)

args = [step.args for step in plan.steps]
assert ("install", "-r", "requirements/export.txt") in args
assert ("install", "-r", "requirements/tracking.txt") not in args


def test_ui_only_never_adds_extras() -> None:
"""--ui-only deliberately omits the ML stack even with --full."""
system = SystemInfo("Linux", "x86_64", ())

plan = plan_install(system, ui_only=True, full=True)

assert plan.profiles == ("ui",)
args = [step.args for step in plan.steps]
assert ("install", "-r", "requirements/tracking.txt") not in args
assert ("install", "-r", "requirements/export.txt") not in args


# ---------------------------------------------------------------------------
# Windows auto-select
# ---------------------------------------------------------------------------
Expand Down
56 changes: 55 additions & 1 deletion tools/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,25 @@ def plan_install(
ui_only: bool = False,
ci: bool = False,
upgrade_pip: bool = False,
with_tracking: bool = False,
with_export: bool = False,
full: bool = False,
) -> InstallPlan:
"""Build a deterministic pip plan without running it."""
"""Build a deterministic pip plan without running it.

The default install is torch-free: the heavy boxmot (tracking) and
ultralytics (export) extras are opt-in via ``--with-tracking`` /
``--with-export`` / ``--full``. ``--dev`` pulls them in through dev.txt
(the test suite needs them), so they are not added again here when dev is
selected.
"""
if ui_only and packaging:
raise ValueError("--ui-only and --packaging target different environments.")
# dev.txt already references tracking.txt + export.txt, so contributors and
# CI (--dev) always get them. The explicit extras only matter for non-dev
# installs that opt in.
want_tracking = with_tracking or full
want_export = with_export or full

requested = "cpu" if ci and accelerator == "auto" else accelerator
selected = None if ui_only else _resolve_accelerator(system, requested)
Expand Down Expand Up @@ -305,6 +320,27 @@ def plan_install(
if dev:
profiles.append("dev")
steps.append(_requirement_step("dev"))
# The torch-heavy extras. dev.txt already references both, so only add them
# explicitly when opted in without --dev (avoids a redundant pip step). They
# are skipped in --ui-only mode, which deliberately omits the ML stack.
if not ui_only and not dev:
if want_tracking:
profiles.append("tracking")
steps.append(_requirement_step("tracking"))
notes.append(
"tracking: boxmot adds BoT-SORT/DeepOCSORT/ByteTrack + OSNet ReID (pulls in torch)."
)
if want_export:
profiles.append("export")
steps.append(_requirement_step("export"))
notes.append(
"export: ultralytics adds the YOLO11 .pt → ONNX export fallback (pulls in torch)."
)
if not ui_only and not dev and not (want_tracking or want_export):
notes.append(
"Lean torch-free default: detection + IoU tracking only. Add --full"
" (or --with-tracking / --with-export) for boxmot/ultralytics."
)
if packaging:
profiles.append("packaging")
steps.append(_requirement_step("packaging"))
Expand Down Expand Up @@ -372,6 +408,21 @@ def _build_parser() -> argparse.ArgumentParser:
parser.add_argument(
"--ci", action="store_true", help="Use hardware-independent CI dependency choices."
)
parser.add_argument(
"--with-tracking",
action="store_true",
help="Add the boxmot tracking extra (BoT-SORT/DeepOCSORT/ReID; pulls in torch).",
)
parser.add_argument(
"--with-export",
action="store_true",
help="Add the ultralytics export extra (.pt → ONNX fallback; pulls in torch).",
)
parser.add_argument(
"--full",
action="store_true",
help="Add both torch-heavy extras (tracking + export). Default install is torch-free.",
)
parser.add_argument(
"--upgrade-pip", action="store_true", help="Upgrade pip before installing profiles."
)
Expand All @@ -396,6 +447,9 @@ def main(argv: Sequence[str] | None = None) -> int:
ui_only=args.ui_only,
ci=args.ci,
upgrade_pip=args.upgrade_pip,
with_tracking=args.with_tracking,
with_export=args.with_export,
full=args.full,
)
except ValueError as exc:
parser.error(str(exc))
Expand Down
Loading