Skip to content

Configuration

A config directory describes one rig. It holds:

  • one octacam_config.toml — camera names, display layout, and the recording/encoding/transfer settings, plus the camera backend;
  • one per-camera sensor parameter file<serial>.pfs for Basler, <serial>.txt (the native GenApi feature-persistence TSV) for FLIR/GenICam, written by the GUI's Save… dialog.

Everything below is optional and has a sensible default — an empty or missing octacam_config.toml uses all detected cameras with defaults. octacam parses the file leniently: a malformed value is warned about and falls back to its default rather than crashing the rig.

See configs/ for complete, working examples.

Scaffolding a config

You rarely have to write the file by hand. octacam config walks you through it: it auto-detects the connected cameras (through the backend cascade, so a mixed Basler + FLIR + GenICam rig is picked up in one go), prompts for the record and transfer settings, writes an octacam_config.toml, and snapshots each camera's current sensor parameters into a per-camera file.

octacam config <config_dir>    # or omit the dir to be prompted for a name

By default the wizard opens each detected camera once to save its current sensor parameters into a <serial>.pfs (Basler) or <serial>.txt (FLIR/GenICam) file. A camera that is busy — held by a live session — is skipped with a warning; you can capture its parameters later from the GUI's Save… dialog. Pass --no-snapshot-params to skip that step entirely (enumeration only, no camera is opened). Pass --backend basler|flir|spinnaker|pycameleon|fake to pin the rig to one backend instead of auto-detecting, or --force to overwrite an existing file. The wizard deliberately leaves the visual settings — per-camera window placement, rotation, and the grid — to octacam gui, which tunes them against a live preview; run it next on the new directory. Everything the wizard writes stays hand-editable afterward.

Top level

# backend = "auto"   # "auto" (default) | "basler" | "flir" | "spinnaker" | "pycameleon" | "fake"

backend is optional. Omit it (or set "auto") and the rig runs the preference cascade: each camera is claimed by the best available driver that sees it (vendor SDK for Basler/FLIR → the Spinnaker C-API tier → the always-present pycameleon floor), so Basler, FLIR, and other GenICam cameras can run together in one config, each keeping its own parameter-file format. Set a concrete value to pin the rig to a single backend. See Camera backends.

[record]

Controls capture and how frames are written.

[record]
fps = 100.0
duration = 5.0
duration_unit = "seconds"      # frames | seconds | minutes | hours
trigger_source = "software"    # software | managed | external

directory = "/data/octacam"
relative_directory = "%y%m%d-genotype/Fly1/001-bhv"   # strftime template

save_method = "ffmpeg"         # ffmpeg | raw
ffmpeg_params = "-c:v libx264 -preset ultrafast -crf 18 -pix_fmt gray"
save_transformed = true
save_timestamps = false
Key Default Meaning
fps 100.0 Frame rate.
duration 5.0 Recording length, in duration_unit.
duration_unit "seconds" frames | seconds | minutes | hours.
trigger_source "software" software, managed (octacam drives the hardware trigger), or an external hardware trigger.
preview_trigger_source "auto" How preview is triggered so it approximates the recording: auto (mirror trigger_source), software, or free_running.
directory "./" Base save directory.
relative_directory "" Sub-path appended to directory; a strftime template (e.g. %y%m%d/…), so trials sort into a date/subject/trial tree.
save_method "ffmpeg" ffmpeg (encoded video) or raw (a .raw byte dump per camera).
ffmpeg_params ultrafast x264, see above Encoder args used at record time.
save_transformed true Bake each camera's rotation/flips into the file (see Recording).
save_timestamps false Also write a single compressed per-frame timestamp file (timestamps.npz) covering all cameras.

[transcode]

Encoder args octacam process uses to re-encode recordings to archival mp4. Usually a slower, higher-quality preset than the record-time params.

[transcode]
ffmpeg_params = "-c:v libx264 -preset veryslow -crf 20 -pix_fmt gray"

[transfer]

Where octacam process copies finished outputs. Omit the whole section to disable transfer.

[transfer]
directory = "/mnt/store/matthias"    # strftime %-codes expand here too
checksum = true                      # content-verify each copy (default)
Key Default Meaning
directory "" Destination base folder; recordings mirror into it under their relative directory. Blank disables transfer.
checksum true blake2b content-verify each copy. false = faster size-only verify.

See Processing → Transfer.

[[cameras]]

One entry per camera, keyed by serial number. Pins each camera's name and its place in the preview/grid layout. With no [[cameras]] entries, every detected camera is used with auto-assigned names and a default layout.

[[cameras]]
serial_number = "40001978"
name = "camera_LF"
scale_x = 1
scale_y = 1
rotation_deg = 0
window_x = 0.5
window_y = 0.25
window_width = 0.5
window_height = 0.25
Key Default Meaning
serial_number — (required) The camera's serial number.
name "" Display name; also the name you use in grid layouts.
scale_x, scale_y 1.0 Preview scale.
rotation_deg 0.0 Display rotation (baked into recordings when save_transformed).
window_x, window_y, window_width, window_height -1.0 Preview tile placement as fractions of the canvas; -1 means auto-place.
center_x, center_y false Auto-center the sensor ROI on that axis: OffsetX/OffsetY are derived from the sensor and ROI size and recomputed when the ROI changes.

Tip

You normally set these from the GUI's View and Camera tabs and save them back, rather than editing the TOML by hand.

[[visualization]]

Defines the composite grid video(s) octacam process builds. List several entries to produce several grids. See Processing → Grid video.

[[visualization]]
name = "grid.mp4"            # output filename inside each recording folder
layout = [
    ["camera_LF", "",          "camera_RF"],
    ["camera_LM", "camera_F",  "camera_RM"],
    ["camera_LH", "",          "camera_RH"],
]
# ffmpeg_params = ""         # optional per-grid encoder override

Each cell is a camera name; "" is a black fill. All rows must have the same number of columns. With no [[visualization]], a near-square layout is derived from the rig's cameras.

[[plugins]]

Enables opt-in plugins. The default launch loads none.

# Bare names work too: plugins = ["flywheel"]
[[plugins]]
name = "flywheel"
options = { device = "/dev/ttyACM0", baud = 115200 }

[gui]

[gui]
display_refresh_interval_ms = 33     # preview refresh cadence (~30 Hz)
theme = "dark"                       # "dark" | "light" rig default; the per-browser toggle overrides it

Validate a config

Check a directory before recording — this cross-checks declared vs detected cameras and resolves the save/transfer paths:

octacam doctor <config_dir>

See doctor.