The official implementation is available on
GitHub .
Zero-Shot Depth from Defocus
(*Equal Contribution)
Roadmap
⏳ Release FOSSA training code (Coming April 2026)
✅ Release FOSSA evaluation code
✅ Release ZEDD dataset and test server
Installation & Setup
Step 1: Create and activate conda environment
1 conda create -n fossa python = 3.8
2 conda activate fossa
Step 2: Install Dependencies
pip install -r requirements.txt
Step 3: Build PowerExpPSF CUDA Extension
This is required for training and evaluation with synthetic defocus effects.
Build steps
1 cd power_exp_psf
2
3 # Build and install the extension
4 python setup.py build_ext --inplace
5
6 # Verify successful installation
7 python - << 'PY'
8 import torch
9 try:
10 import power_exp_psf_cuda
11 import os
12 path = power_exp_psf.__file__
13 if os.path.exists(path):
14 print(f"SUCCESS: power_exp_psf_cuda loaded from {path}")
15 else:
16 print(f"ERROR: module loaded but file does not exist at {path}")
17 except Exception as e:
18 print(f"IMPORT FAILED: {e}")
19 PY
20
21 cd ..
22
23 # Add power_exp_psf as a search directory for imports
24 export PYTHONPATH = $PWD /power_exp_psf: $PYTHONPATH
Step 4: Load datasets into dataset/datasets
Datasets download instructions
📦 HAMMER
Download:
HAMMER Dataset prepared by
MoGe2 .
1 cd dataset/datasets
2 wget https://huggingface.co/datasets/Ruicheng/monocular-geometry-evaluation/resolve/main/HAMMER.zip
3 unzip HAMMER.zip
4 rm -f HAMMER.zip
5 cd .. / ..
📦 DDFF-12
Data split
1 cd dataset/datasets
2 mkdir ddff12_val_generation
3 cd ddff12_val_generation
4 mkdir third_part
Then, in your browser, navigate to the
DFV Split (MS Sharepoint) prepared by
DFF-DFV .
Click the download button. Then, copy the downloaded "my_ddff_trainVal.h5" file into dataset/datasets/ddff12_val_generation and rename it to "dfv_trainVal.h5".
Intrinsics matrix:
The intrinsics matrix is also
provided by DFV(.mat file) .
Download the "raw file" in the GitHub UI and place the downloaded IntParamLF.mat at "dataset/datasets/ddff_val_generation/third_part/".
At the end, the "dataset" directory should look like this (of which only ddff12_val_generation and HAMMER you need to create).
Expected format:
1 dataset/
2 ├── datasets/
3 │ ├── ddff12_val_generation/
4 │ │ ├── dfv_trainVal.h5
5 │ │ └── third_part/
6 │ │ └── IntParamLF.mat
7 │ ├── HAMMER/
8 │ │ └── scene2_traj1_1/
9 │ │ │ └── 000000/
10 │ │ │ │ └── depth.png
11 │ │ │ │ └── intrinsics.json
12 │ │ │ │ └── meta.json
13 │ │ │ └── ...
14 │ │ └── ...
15 │ │ └── .index.txt
16 │ └── splits/
17 │ └── infinigen_defocus/
18 │ └── val.json
19 ├── __init__.py
20 ├── base.py
21 ├── ddff12_val.py
22 ├── hammer.py
23 ├── infinigen_defocus.py
24 ├── uniformat.py
25 └── zedd.py
Datasets that are loaded from HuggingFace (no user downloading necessary)
Note: the first time that evaluation is done on these datasets will take some time for the zip file to download and get unpacked. If you are downloading the zip file manually, note that you will have to delete the outer folder created by the unzipped file to achieve the above file structure (deleting of the outer folder is done automatically in the provided code).
Final expected format:
1 dataset/
2 ├── datasets/
3 │ ├── ddff12_val_generation/
4 │ │ ├── dfv_trainVal.h5
5 │ │ └── third_part/
6 │ │ └── IntParamLF.mat
7 │ ├── defocus_uniformat/
8 │ │ ├── diode/
9 │ │ │ ├── diode_indoor_v2/
10 │ │ │ │ ├── 000000.npy
11 │ │ │ │ ├── 000001.npy
12 │ │ │ │ └── ...
13 │ │ │ └── diode_outdoor_v2/
14 │ │ │ ├── 000000.npy
15 │ │ │ ├── 000001.npy
16 │ │ │ └── ...
17 │ │ └── ibims/
18 │ │ ├── 000000.npy
19 │ │ ├── 000001.npy
20 │ │ └── ...
21 │ ├── HAMMER/
22 │ │ ├── scene2_traj1_1/
23 │ │ │ ├── 000000/
24 │ │ │ │ ├── depth.png
25 │ │ │ │ ├── intrinsics.json
26 │ │ │ │ └── meta.json
27 │ │ │ └── ...
28 │ │ ├── ...
29 │ │ └── .index.txt
30 │ ├── infinigen_defocus/
31 │ │ ├── 1a4897de_1/
32 │ │ │ ├── cam_all_in_focus.npz
33 │ │ │ ├── cam_ap_1.40_fd_0.80.npz
34 │ │ │ ├── ...
35 │ │ │ ├── depth.npy
36 │ │ │ ├── image_all_in_focus.png
37 │ │ │ └── image_ap_1.40_fd_0.80.png
38 │ │ └── ...
39 │ ├── ZEDD/
40 │ │ ├── test/
41 │ │ │ ├── test_0001/
42 │ │ │ │ ├── focus_stack/
43 │ │ │ │ │ ├── img_run_1_motor_6D3E_aperture_F1.4.jpg
44 │ │ │ │ │ ├── img_run_1_motor_6D3E_aperture_F2.0.jpg
45 │ │ │ │ │ └── ...
46 │ │ │ │ └── gt/
47 │ │ │ │ └── K.txt
48 │ │ │ └── ...
49 │ │ └── val/
50 │ │ ├── val_0001/
51 │ │ │ ├── focus_stack/
52 │ │ │ │ ├── img_run_1_motor_6D3E_aperture_F1.4.jpg
53 │ │ │ │ ├── img_run_1_motor_6D3E_aperture_F2.0.jpg
54 │ │ │ │ └── ...
55 │ │ │ └── gt/
56 │ │ │ ├── depth_vis.jpg
57 │ │ │ ├── depth.npy
58 │ │ │ ├── K.txt
59 │ │ │ └── overlay.jpg
60 │ │ └── ...
61 │ └── splits/
62 │ └── infinigen_defocus/
63 │ └── val.json
64 ├── __init__.py
65 ├── base.py
66 ├── ddff12_val.py
67 ├── hammer.py
68 ├── infinigen_defocus.py
69 ├── uniformat.py
70 └── zedd.py
📦 ZEDD
📦 Infinigen Defocus
📦 iBims-1 and DIODE
Validation Quickstart
Running Validation
The easiest way to validate is using the distributed validation script:
bash dist_val.sh --encoder [VITS/VITB] --resumed_from [NAME OF PARAMETERS] --val_loader_config_choice [VAL_CONFIG_CHOICE]
Available Validation Configurations
See config/validation_configs.py for all predefined validation setups:
Model Loading Options
Option 1: Load from HuggingFace Hub (recommended)
resumed_from='model_name' # automatically pull from venkatsubra/model_name
Option 2: Load from local path
resumed_from='/path/to/model.pth'
Reproducing Numbers in the Paper
🔹 ViT-S
Table 2
ZEDD
Note: The results below are on the validation split, so do not match the numbers in Table 2 on the test split
1 bash dist_val.sh --encoder vits --resumed_from fossa-vits \
2 --val_loader_config_choice zedd_F2_8_fixed_fd_0_2_4_6_8
D1.05 D1.15 D1.25 abs_rel 0.4450 0.7866 0.8858 0.0985
Infinigen
1 bash dist_val.sh --encoder vits --resumed_from fossa-vits \
2 --val_loader_config_choice infinigen_defocus_F1_4_fixed_fd_0_8,1_7,3_0,4_7,8_0
D1.05 D1.15 D1.25 abs_rel 0.5201 0.8635 0.9400 0.0847
Table 3
iBims-1
1 bash dist_val.sh --encoder vits --resumed_from fossa-vits \
2 --val_loader_config_choice ibims_F1_4_adaptive_fd
D1.05 D1.15 D1.25 abs_rel 0.5193 0.8502 0.9540 0.0745
DIODE
1 bash dist_val.sh --encoder vits --resumed_from fossa-vits \
2 --val_loader_config_choice diode_F1_4_adaptive_fd
D1.05 D1.15 D1.25 abs_rel 0.4105 0.6649 0.7661 0.1778
HAMMER
1 bash dist_val.sh --encoder vits --resumed_from fossa-vits \
2 --val_loader_config_choice hammer_F1_4_adaptive_fd
D1.05 D1.15 D1.25 abs_rel 0.6006 0.9889 0.9987 0.0440
Table 4
DDFF12 (Base Model)
1 bash dist_val.sh --encoder vits --resumed_from fossa-vits \
2 --val_loader_config_choice ddff12_val
MSE RMSE AbsRel SqRel D1 D2 D3 0.0015 0.0352 0.2676 0.0119 0.3462 0.8119 0.9544
DDFF12 (Finetuned)
1 bash dist_val.sh --encoder vits --resumed_from fossa-vits-ddff-finetuned \
2 --val_loader_config_choice ddff12_val
MSE RMSE AbsRel SqRel D1 D2 D3 0.0004 0.0183 0.1076 0.0045 0.9363 0.9829 0.9908
🔹 ViT-B
Table 2
ZEDD
Note: The results below are on the validation split, so do not match the numbers in Table 2 on the test split
1 bash dist_val.sh --encoder vitb --resumed_from fossa-vitb \
2 --val_loader_config_choice zedd_F2_8_fixed_fd_0_2_4_6_8
D1.05 D1.15 D1.25 abs_rel 0.4317 0.8101 0.9194 0.0957
Infinigen
1 bash dist_val.sh --encoder vitb --resumed_from fossa-vitb \
2 --val_loader_config_choice infinigen_defocus_F1_4_fixed_fd_0_8,1_7,3_0,4_7,8_0
readme
D1.05 D1.15 D1.25 abs_rel 0.4199 0.8199 0.9355 0.0908
Table 3
iBims-1
1 bash dist_val.sh --encoder vitb --resumed_from fossa-vitb \
2 --val_loader_config_choice ibims_F1_4_adaptive_fd
D1.05 D1.15 D1.25 abs_rel 0.5548 0.8719 0.9633 0.0701
DIODE
1 bash dist_val.sh --encoder vitb --resumed_from fossa-vitb \
2 --val_loader_config_choice diode_F1_4_adaptive_fd
D1.05 D1.15 D1.25 abs_rel 0.4127 0.6692 0.7786 0.1601
HAMMER
1 bash dist_val.sh --encoder vitb --resumed_from fossa-vitb \
2 --val_loader_config_choice hammer_F1_4_adaptive_fd
D1.05 D1.15 D1.25 abs_rel 0.9377 0.9974 0.9993 0.0172
Table 4
DDFF12 (Base Model)
1 bash dist_val.sh --encoder vitb --resumed_from fossa-vitb \
2 --val_loader_config_choice ddff12_val
MSE RMSE AbsRel SqRel D1 D2 D3 0.0013 0.0324 0.2105 0.0107 0.6075 0.9206 0.9679
DDFF12 (Finetuned)
1 bash dist_val.sh --encoder vitb --resumed_from fossa-vitb-ddff-finetuned \
2 --val_loader_config_choice ddff12_val
MSE RMSE AbsRel SqRel D1 D2 D3 0.0003 0.0148 0.1088 0.0025 0.9322 0.9866 0.9939
Submitting to ZEDD Test Server
For ZEDD test set, save model outputs in the following format:
A single .zip file containing exactly 50 .npy files at the root level (no subdirectories)
Files must be named zedd_output_0001.npy through zedd_output_0050.npy
Each .npy file must be a 2-D float array of shape (H=1216, W=1824) — no channel dimension
All values must be finite (no NaN or Inf)
Please run the following command to check the file format before submitting to the server:
python zedd_test/zedd_check_format.py --zip [YOUR_ZIP_FILE]
Here is an example to compile the zip file for FOSSA ViT-S:
bash dist_test.sh --encoder=vits --resumed_from fossa-vits --val_loader_config_choice zedd_test_F2_8_fixed_fd_0_2_4_6_8 --experiment_name=FOSSA --zedd_test_output_dir=zedd_outputs
Troubleshooting
PowerExpPSF building
❌ Error: nvcc not found / CUDA extension build fails
If you see an error like: "error: [Errno 2] No such file or directory: '/usr/local/cuda-12.1/bin/nvcc'" or "nvcc not found", this means your environment does not have a CUDA toolkit with nvcc available .
✅ Fix: Load a valid CUDA toolkit and set environment variables
On cluster environments, load an available CUDA module:
1 module avail cuda
2 module load cudatoolkit/12.6 # or closest version to your PyTorch CUDA
3 export CUDA_HOME = /usr/local/cuda-12.6
4 export PATH = " $CUDA_HOME /bin: $PATH "
5 export LD_LIBRARY_PATH = " $CUDA_HOME /lib64: $LD_LIBRARY_PATH "
Then verify:
1 which nvcc
2 nvcc --version
Then retry:
python setup.py build_ext --inplace
❌ Error: ModuleNotFoundError: No module named 'power_exp_psf_cuda'
If you see an error like: "ModuleNotFoundError: No module named 'power_exp_psf_cuda'", this means your environment does not know where to search for the power_exp_psf_cuda module.
✅ Fix: Add the module to PYTHONPATH
From your project root, run:
export PYTHONPATH=$PWD/power_exp_psf:$PYTHONPATH
Then retry your script.
Acknowledgments