The Command Line

vcal calibrates a folder of images without a line of code: it drafts the dataset manifest, checks it, detects the target, calibrates, and writes the result and its quality report as JSON. It runs the same library calls as Calibrate Your Own Images, so the numbers are the same.

cargo install vision-calibration-cli   # or: pip install vision-calibration

The Rust crate and the Python package install the same program.

CommandDoes
vcal init <folder>drafts <folder>/dataset.toml from the file names
vcal check <manifest>checks the manifest and its images, without detecting
vcal run <manifest>detects, calibrates, writes calibration.json and quality.json (--report adds report.html)
vcal sample listlists the sample datasets
vcal sample fetch <id>downloads a sample dataset and prints its manifest's path

vcal <command> --help lists each command's options.

A folder of images

vcal init data/my_camera
wrote data/my_camera/dataset.toml
fill in, then delete `_unresolved`:
  target

The draft lists what the file names cannot tell, the board above all, under _unresolved. Describe the board (The Dataset Manifest) and delete the list:

[target]
kind = "chessboard"
rows = 6            # inner corners down
cols = 9            # inner corners across
square_size_m = 0.025

vcal check then reads the manifest and each image's header. It reports a manifest that is incomplete or invalid, a camera whose images it cannot find, and a camera whose images differ in size, all before any detection:

$ vcal check data/my_camera/dataset.toml
data/my_camera/dataset.toml: planar_intrinsics
  camera cam0: 640 × 480 px
ok

vcal run calibrates. On the 13 views of the opencv_left sample, fetched to ~/.cache/vision-calibration, it prints:

$ vcal run ~/.cache/vision-calibration/opencv_left/dataset.toml
planar_intrinsics: 13 of 13 views used
camera 0 (left), 640 × 480 px:
  fx = 534.108 ± 0.930 px
  fy = 534.155 ± 0.966 px
  cx = 341.029 ± 1.075 px
  cy = 233.586 ± 1.144 px
verdict: warn
  not_applicable variance_factor: no expected feature noise was stated (expected_feature_noise_px)
  warn projection_sigma camera 0: projection σ up to 5.490 px over the 640×480 image (centre 1.146 px, corners 5.490 px)
wrote ~/.cache/vision-calibration/opencv_left/calibration.json and ~/.cache/vision-calibration/opencv_left/quality.json

Each parameter comes with its σ, and the verdict with the checks that did not pass (Judging a Result). Here the 13 views leave the image corners uncertain by 5 px; Capturing Calibration Images says which views would fix that. A view left out of the calibration is listed with its reason, such as a chessboard whose corners do not reach every edge of the board.

calibration.json is the workflow's export, the same JSON the library and the desktop app write, and quality.json is the quality report. --report adds report.html, all of it as one page with the residual and projection-σ figures (The Calibration Report). -o <dir> writes them elsewhere. Detections are cached in .detections next to the manifest, so a second run skips detection; --redetect detects again.

Configuration

Without a configuration file the workflow runs with its defaults: a pinhole camera with Brown-Conrady distortion. -c <file> changes the defaults the file names and keeps the rest. The file is TOML or JSON and holds the workflow's *Config fields. A fisheye camera needs a fisheye model:

# fisheye.toml
camera.model = { projection = "equidistant", distortion = "kannala_brandt4", sensor = "identity" }
vcal run "$(vcal sample fetch opencv_fisheye_stereo)" -c fisheye.toml

On that sample the default model leaves each focal length uncertain by 14 px; the fisheye model brings σ(fx) to 1.1 px. A field the workflow does not have is an error, so a misspelt name never passes silently. The fields are those of Configuring a Run and of each workflow's chapter.

Sample datasets

vcal sample list
vcal run "$(vcal sample fetch kuka_1)" -o out/kuka

fetch downloads a sample from its publisher, verifies every file's SHA-256 and prints the path of its manifest, so it composes with run. A second fetch reuses the cache: VISION_CALIBRATION_DATA, else vision-calibration in the platform's cache directory, or --cache <dir>.

Exit status

StatusMeaning
0done; for run, the verdict is pass or warn
1an error, printed on standard error
2a wrong command line
3run wrote its files, but the verdict is fail
130interrupted with Ctrl-C: the run stopped and wrote nothing

A script can stop on a failed calibration with vcal run ... || exit.

Progress and Ctrl-C

On a terminal, vcal run keeps one line of standard error up to date: the images detected (detecting 12/40), then each step and its solver iterations (optimize: iteration 7/50, cost 1.2345e2). Piped or redirected, it prints no progress. Ctrl-C stops the run at the next image or iteration, prints interrupted and exits with status 130; a second Ctrl-C exits at once.

Limits

The laser workflows (laserline_device, rig_laserline_device, rig_handeye_laserline) need a laser-line extractor, which the library takes from code (Laser Datasets); vcal run refuses them before any detection. Calibrate them from Rust or Python.