Files

02 Calibration

Two-step calibration pipeline:

Step Script What it does
1. Detection detect_features.py Chessboard corners / IR ellipses → JSON next to each image
2. Calibration calibrate.py Mono intrinsics per camera + stereo lc vs rc/rg/ir

main.py runs both steps by default (--step all).


Troubleshooting flag

All calibration scripts accept --troubleshooting (default: off).

--troubleshooting Logs Disk output
False (default) Minimal summary per camera / stereo pair Step 1: *.json only (required for step 2). Step 2: params/ only
True Detailed per-image / per-pair logs, progress bars Step 1: + corners/<camera>/ overlays. Step 2: + pairing_reports/, rectified/
# Default — minimal logs, only params/ from step 2
python main.py --project Olsen_wings --date 2026-05-12 --calib_name calib1

# Debug — verbose logs + intermediate folders
python main.py --project Olsen_wings --date 2026-05-12 --calib_name calib1 --troubleshooting

Legacy mode (--legacy) also respects --troubleshooting (corners, local_coords, images_ncb, rectified).


All CLI parameters (reference)

Parameter Default Used in
--project required all
--date required all
--calib_name calib1 all
--chessboard_size 8,7 all
--square_size 0.045 all
--left_chessboard_size = --chessboard_size all
--right_chessboard_size = --chessboard_size all
--left_square_size = --square_size all
--right_square_size = --square_size all
--preprocessing None step 1 (G, C, T chain)
--cameras all present detect_features.py
--ir_mode auto step 1 (auto / chessboard / ellipse)
--step all main.py (detect/calibrate/all); calibrate.py (mono/stereo/all)
--left_camera lc step 2 stereo (lc / lc-ir)
--time_window 0.1 step 2 stereo (seconds)
--partners rc,rg,ir step 2 stereo
--legacy off main.py only
--right_camera rc main.py --legacy only
--troubleshooting off all (False = minimal; True = debug output)

Folder structure

~/Calib-data/<project>/<date>/<calib_name>/
├── lc/
│   ├── lc_1778599872850705.bmp
│   └── lc_1778599872850705.json      ← step 1 (always)
├── rc/
├── rg/   (or rgb/)
├── ir/   (or IR/)
├── corners/                          ← step 1, only with --troubleshooting
├── pairing_reports/                  ← step 2, only with --troubleshooting
├── rectified/                        ← step 2, only with --troubleshooting
└── params/                           ← step 2 (always)
    ├── lc_intrinsics.npz
    ├── rc_intrinsics.npz
    ├── lc-rc_parameters.npz
    ├── lc-rc_stereo_cam_model.yaml
    ├── lc-rc_Q.cvstore
    ├── lc-rg_*
    └── lc-ir_*

Nested layout (<calib_name>/images/lc/, …) is also supported.


Quick start (full pipeline)

cd ~/Speckle-Scanner/02_Calibration

python main.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --chessboard_size 8,7 --square_size 0.045

Or run steps separately:

# Step 1 — detect features, write JSON
python detect_features.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --chessboard_size 8,7 --square_size 0.045

# Step 2 — calibrate from JSON (writes params/ only)
python calibrate.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --chessboard_size 8,7 --square_size 0.045 \
  --time_window 0.1

Step 1 — Feature detection (per camera)

For every image in each camera folder (lc, rc, rg, ir, lc-ir):

  • Detects chessboard corners (default for lc/rc/rg)
  • For IR: tries chessboard first (--ir_mode auto), falls back to ellipse center
  • Writes <image>.json in the same folder as the image (always, even without --troubleshooting)

LC only

python detect_features.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --cameras lc \
  --chessboard_size 8,7 --square_size 0.045 \
  --left_chessboard_size 8,7 --left_square_size 0.045 \
  --preprocessing None

RC only

python detect_features.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --cameras rc \
  --chessboard_size 8,7 --square_size 0.045 \
  --right_chessboard_size 8,7 --right_square_size 0.045 \
  --preprocessing None

RG only

python detect_features.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --cameras rg \
  --chessboard_size 8,7 --square_size 0.045 \
  --right_chessboard_size 8,7 --right_square_size 0.045 \
  --preprocessing None

IR only

python detect_features.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --cameras ir \
  --chessboard_size 8,7 --square_size 0.045 \
  --right_chessboard_size 8,7 --right_square_size 0.045 \
  --preprocessing C \
  --ir_mode auto

LC-IR folder only

python detect_features.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --cameras lc-ir \
  --chessboard_size 8,7 --square_size 0.045 \
  --left_chessboard_size 8,7 --left_square_size 0.045 \
  --preprocessing None

All cameras

python detect_features.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --chessboard_size 8,7 --square_size 0.045 \
  --left_chessboard_size 8,7 --left_square_size 0.045 \
  --right_chessboard_size 8,7 --right_square_size 0.045 \
  --preprocessing None \
  --ir_mode auto

Step 1 with troubleshooting

python detect_features.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --cameras lc,rc,ir \
  --chessboard_size 8,7 --square_size 0.045 \
  --preprocessing C \
  --ir_mode auto \
  --troubleshooting

JSON contents (chessboard example)

{
  "version": 1,
  "image": "lc_1778599872850705.bmp",
  "camera_folder": "lc",
  "feature_type": "chessboard",
  "success": true,
  "board_size": [8, 7],
  "square_size": 0.045,
  "timestamp_sec": 1778599872.850705,
  "pair_key": "1778599872850705",
  "corners": [[412.3, 287.1], ...]
}

Step 2 — Calibration

2a. Mono intrinsics

Reads chessboard JSONs from each camera folder, runs cv2.calibrateCamera, saves:

  • params/<camera>_intrinsics.npz
  • params/<camera>_intrinsics.yaml

Requires ≥ 3 successful chessboard detections per camera.

2b. Stereo calibration

  • Left camera: lc by default (--left_camera)
  • Partners: rc, rg, ir — each available folder is calibrated against lc
  • Pairing: time-window match (--time_window, default 0.1 s), then filename pair_key fallback for IR scan ids
  • Uses mono intrinsics with CALIB_FIX_INTRINSIC
  • Saves lc-rc_*, lc-rg_*, lc-ir_* under params/

Full step 2 (mono + all stereo pairs)

python calibrate.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --step all \
  --left_camera lc \
  --partners rc,rg,ir \
  --time_window 0.1 \
  --chessboard_size 8,7 --square_size 0.045 \
  --left_chessboard_size 8,7 --left_square_size 0.045 \
  --right_chessboard_size 8,7 --right_square_size 0.045

Stereo: LC ↔ RC only

python calibrate.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --step stereo \
  --left_camera lc \
  --partners rc \
  --time_window 0.1 \
  --chessboard_size 8,7 --square_size 0.045

Stereo: LC ↔ RG only

python calibrate.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --step stereo \
  --left_camera lc \
  --partners rg \
  --time_window 0.1 \
  --chessboard_size 8,7 --square_size 0.045

Stereo: LC ↔ IR only

python calibrate.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --step stereo \
  --left_camera lc \
  --partners ir \
  --time_window 0.1 \
  --chessboard_size 8,7 --square_size 0.045

Stereo: left = LC-IR folder

python calibrate.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --step stereo \
  --left_camera lc-ir \
  --partners rc,rg,ir \
  --time_window 0.1 \
  --chessboard_size 8,7 --square_size 0.045 \
  --left_chessboard_size 8,7 --left_square_size 0.045 \
  --right_chessboard_size 8,7 --right_square_size 0.045

Mono intrinsics only

python calibrate.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --step mono \
  --chessboard_size 8,7 --square_size 0.045 \
  --left_chessboard_size 8,7 --left_square_size 0.045 \
  --right_chessboard_size 8,7 --right_square_size 0.045

Step 2 with troubleshooting

python calibrate.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --step all \
  --time_window 0.1 \
  --chessboard_size 8,7 --square_size 0.045 \
  --troubleshooting

Writes params/ plus pairing_reports/<pair>.txt and rectified/<pair>/.


Full pipeline (main.py)

python main.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --step all \
  --left_camera lc \
  --partners rc,rg,ir \
  --time_window 0.1 \
  --chessboard_size 8,7 --square_size 0.045 \
  --left_chessboard_size 8,7 --left_square_size 0.045 \
  --right_chessboard_size 8,7 --right_square_size 0.045 \
  --preprocessing None \
  --ir_mode auto

With troubleshooting:

python main.py \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --troubleshooting \
  --chessboard_size 8,7 --square_size 0.045

Legacy one-shot mode

The old in-memory flow (single --right_camera, filename pairing) still works:

# LC-RC
python main.py --legacy \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --left_camera lc --right_camera rc \
  --chessboard_size 8,7 --square_size 0.045

# LC-RG
python main.py --legacy \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --left_camera lc --right_camera rg \
  --chessboard_size 8,7 --square_size 0.045

# LC-IR
python main.py --legacy \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --left_camera lc --right_camera ir \
  --chessboard_size 8,7 --square_size 0.045 \
  --preprocessing C

# LC-IR folder + IR partner (with debug output)
python main.py --legacy \
  --project Olsen_wings --date 2026-05-12 --calib_name calib1 \
  --left_camera lc-ir --right_camera ir \
  --chessboard_size 8,7 --square_size 0.045 \
  --preprocessing C --troubleshooting

Dependencies

pip install -r ~/Speckle-Scanner/02_Calibration/requirements.txt
# or full pipeline:
pip install -r ~/Speckle-Scanner/requirements.txt

Notes

  • Stereo pairing uses timestamps parsed from filenames (ts… tokens or long numeric ids); ck… suffixes are ignored.
  • Ellipse-only IR JSONs are stored but cannot produce mono intrinsics (need full chessboard grids). Use chessboard IR images for calibration.
  • Per-camera board overrides apply to detection and calibration (--left_chessboard_size, etc.).
  • Re-run step 1 if images change; re-run step 2 freely when tuning time_window or partners.
  • With --troubleshooting off, step 2 writes only params/ (no pairing_reports/, no rectified/).