File size: 8,253 Bytes
42d5516
 
8259c36
 
42d5516
8259c36
 
 
42d5516
8259c36
 
 
 
 
 
 
 
 
 
42d5516
 
8259c36
 
 
 
42d5516
 
8259c36
 
 
 
 
 
 
 
 
 
42d5516
 
 
 
 
8259c36
 
 
 
 
 
42d5516
 
 
8259c36
 
42d5516
 
 
 
 
 
8259c36
42d5516
 
8259c36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42d5516
 
 
 
 
 
 
 
8259c36
42d5516
 
 
 
 
 
 
 
8259c36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42d5516
 
 
8259c36
42d5516
 
8259c36
42d5516
8259c36
 
42d5516
 
 
8259c36
 
 
 
 
 
 
42d5516
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8259c36
 
42d5516
 
 
 
 
8259c36
42d5516
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8259c36
 
 
42d5516
 
8259c36
 
42d5516
 
8259c36
 
42d5516
 
 
 
 
8259c36
 
 
 
 
 
 
 
 
 
 
 
 
 
42d5516
 
 
 
 
8259c36
42d5516
8259c36
 
 
42d5516
 
 
8259c36
42d5516
 
 
 
 
 
 
 
 
 
 
 
 
 
8259c36
 
 
 
 
 
 
 
42d5516
 
 
 
 
8259c36
 
 
 
 
 
42d5516
8259c36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# Depth Anything 3 ONNX

This document describes the Depth Anything 3 (DA3) ONNX export used by
PTMediaServer for image, video, and 2D-to-3D/VR depth estimation.

The exporter is [examples/da3_to_onnx.py](da3_to_onnx.py). It converts the
ONNX-friendly depth branch of DA3 Small/Base into fixed-resolution ONNX Runtime
graphs so inference does not need PyTorch at runtime.

## Upstream

- Official project: <https://github.com/ByteDance-Seed/depth-anything-3>
- This exporter targets the DA3 Main Series `DA3-SMALL` and `DA3-BASE`
  checkpoints.
- The upstream model cards list `DA3-SMALL` and `DA3-BASE` as Apache 2.0.
- These ONNX files are derived from Depth Anything 3 weights and should be used
  according to the upstream license, model cards, and citation requirements.

## Files And Paths

```text
examples/da3_to_onnx.py
examples/da3_README.md
models/DA3/da3_small.onnx
models/DA3/da3_base.onnx
```

The conversion script defaults are currently:

| Purpose | Default |
| --- | --- |
| DA3 source tree | `G:/GIT/debug/VR_Video_Toolbox_NE/tool_2dvr/_vendor/da3` |
| PyTorch weights | `G:/GIT/debug/VR_Video_Toolbox_NE/models/DA3/Small` and `Base` |
| ONNX output | `models/DA3` in this repository |

Canonical output names at the default size:

| File | Variant | Notes |
| --- | --- | --- |
| `da3_small.onnx` | Depth Anything 3 Small | Faster and lighter. |
| `da3_base.onnx` | Depth Anything 3 Base | Larger model, usually better depth quality. |

For non-default export sizes, the script appends the side length:

```text
models/DA3/da3_small_700.onnx
models/DA3/da3_base_1036.onnx
```

## Exported Graph

The converter wraps `DepthAnything3Net.forward(...)` with a singleton view
dimension and these fixed branch settings:

```python
skip_camera=True
skip_sky=True
infer_gs=False
use_ray_pose=False
ref_view_strategy="middle"
```

Only the depth-only sub-graph is exported:

- DINOv2 encoder, ViT-S for Small and ViT-B for Base.
- DualDPT depth head.
- Single-view input, `S=1`, one independent view per frame.
- Dynamic batch axis only.

Camera, sky, and Gaussian-splatting branches are intentionally excluded because
their `torch.quantile`, random sampling, `.item()`, and boolean-mask control
flow are not suitable for this static ONNX trace.

The script also patches DA3 RoPE's `PositionGetter` during export so
`torch.cartesian_prod` is replaced with an ONNX-exportable `meshgrid` equivalent.

## Fixed Square Input

The default input size is `518 x 518`, matching DA3's native `37 x 37` patch
grid with patch size `14`. At this size the learned positional embedding uses
the clean `npatch == N and w == h` path, avoiding bicubic position interpolation
in the exported graph.

Rules:

- Height and width are fixed in each ONNX file.
- Only the batch dimension is dynamic.
- `--size` must be a multiple of `14`.
- Re-export when you need another input side length.

## Input And Output

Default export:

```text
input name : image
input dtype: float32
input shape: [batch, 3, size, size]
layout     : RGB, CHW
range      : ImageNet-normalized float32

output name : depth
output dtype: float32
output shape: [batch, height, width]
```

Folded preprocessing export (`--fold-preprocess`):

```text
input name : image
input dtype: uint8
input shape: [batch, size, size, 3]
layout     : RGB, HWC
range      : 0..255

output name : depth
output dtype: float32
output shape: [batch, height, width]
```

The output is raw DA3 depth, which is distance-like in this project. The
2D-to-3D path treats smaller values as nearer, then resizes, inverts, clips, and
normalizes depth at runtime.

## Preprocessing

For the default float32 ONNX export:

1. Load the image or video frame as RGB.
2. Resize or letterbox to the fixed square export size.
3. Convert to float32 in the `0.0 .. 1.0` range.
4. Apply ImageNet normalization with mean `[0.485, 0.456, 0.406]` and std
   `[0.229, 0.224, 0.225]`.
5. Transpose from HWC to CHW.
6. Add the batch dimension.

For `--fold-preprocess`, the ONNX graph performs steps 3 to 5 internally. The
application still needs to resize or letterbox to `[size, size]` and pass RGB
`uint8` input.

PTMediaServer's `offline.da3_depth.Da3DepthEngine` detects the ONNX input dtype
and supports both contracts. The PyNv hot path requires the folded-preprocess
model because it uploads a `uint8` letterbox canvas.

## Runtime Dependencies

CPU:

```bash
pip install onnxruntime numpy opencv-python
```

GPU:

```bash
pip install onnxruntime-gpu numpy opencv-python
```

## Quick Inference Example

This example is for the default float32 export.

```python
import cv2
import numpy as np
import onnxruntime as ort

model = "models/DA3/da3_small.onnx"
size = 518

mean = np.array([0.485, 0.456, 0.406], dtype=np.float32)
std = np.array([0.229, 0.224, 0.225], dtype=np.float32)

image_bgr = cv2.imread("input.jpg", cv2.IMREAD_COLOR)
image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
resized = cv2.resize(image_rgb, (size, size), interpolation=cv2.INTER_CUBIC)

x = resized.astype(np.float32) / 255.0
x = (x - mean) / std
x = np.transpose(x, (2, 0, 1))[None, ...]

session = ort.InferenceSession(
    model,
    providers=["CUDAExecutionProvider", "CPUExecutionProvider"],
)
depth = session.run(["depth"], {"image": x})[0][0]

depth = cv2.resize(depth, (image_bgr.shape[1], image_bgr.shape[0]))
depth_u8 = cv2.normalize(depth, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
cv2.imwrite("depth.png", depth_u8)
```

For a folded-preprocess model, feed `resized[None, ...]` directly as `uint8`
RGB `[batch, size, size, 3]`.

## Convert From PyTorch Weights

Run the exporter from this repository root. The VR_Video_Toolbox_NE virtual
environment already contains the DA3 PyTorch dependencies:

```bash
G:/GIT/debug/VR_Video_Toolbox_NE/.venv/Scripts/python.exe \
  examples/da3_to_onnx.py --variant both --validate
```

Export one variant:

```bash
python examples/da3_to_onnx.py --variant small --validate
python examples/da3_to_onnx.py --variant base --validate
```

Export folded-preprocess models for PTMediaServer's fast video paths:

```bash
python examples/da3_to_onnx.py --variant both --validate --fold-preprocess
```

Export another fixed input size:

```bash
python examples/da3_to_onnx.py --variant base --size 700 --validate --fold-preprocess
```

Useful options:

```text
--variant small|base|both
--src-root PATH       Folder containing Small/ and Base/ weight directories.
--vendor PATH         Vendored DA3 source root containing depth_anything_3/.
--out-dir PATH        Output folder for da3_*.onnx.
--size 518            Fixed square input side. Must be a multiple of 14.
--opset 18            ONNX opset version.
--device cpu|cuda     Device used for tracing. CPU is the default.
--no-validate         Skip ONNX Runtime validation.
--fold-preprocess     Export uint8 NHWC input with ImageNet normalize inside ONNX.
```

Expected weight layout:

```text
DA3/
  Small/
    model.safetensors
  Base/
    model.safetensors
```

## Validation

When validation is enabled, the converter compares PyTorch output with ONNX
Runtime output and reports:

- output shape
- max absolute error
- mean absolute error
- relative mean error
- active ONNX Runtime providers

The script warns if relative error is higher than `1e-2`.

## Notes

- The ONNX graph is depth-only; it does not export pose, camera, confidence,
  sky segmentation, or Gaussian outputs.
- These exports are fixed-shape models. Re-export for another input side.
- Use input sizes that are multiples of `14`; `518` is the safest default.
- `--fold-preprocess` changes the ONNX input contract and overwrites the same
  output filename unless you also change `--out-dir` or `--size`.
- The output is raw model depth, not metric depth.
- Smaller depth values are treated as nearer in PTMediaServer's 2D-to-3D path.

## Citation

If you use Depth Anything 3 or ONNX exports derived from it in research or a
published project, cite the upstream work:

```bibtex
@article{depthanything3,
  title={Depth Anything 3: Recovering the visual space from any views},
  author={Haotong Lin and Sili Chen and Jun Hao Liew and Donny Y. Chen and Zhenyu Li and Guang Shi and Jiashi Feng and Bingyi Kang},
  journal={arXiv preprint arXiv:2511.10647},
  year={2025}
}
```