Configuration
Every rig has one TOML file: its source, markers, detector settings, outputs and recording. The GUI saves edits back into it automatically, keeping its comments. Configs are validated when loaded; an invalid value is reported with the key’s name, and nothing is changed.
Relative paths in a config are relative to the config file. Edits that change the source, the outputs or the label take effect after Settings → Restart acquisition. Everything else applies to the next frame.
tests/docs.rs checks that every key of the default config appears on this page.
Top level
| Key | Default | Meaning |
|---|---|---|
instance | "rig-a" | Label for the window title, logs and recordings (1–128 characters) |
autosave | true | Save GUI edits automatically, 300 ms after the last change and on close |
preview_fps | 40 | GUI refresh rate, 1–120. Tracking always uses every frame |
[source]
| Key | Default | Meaning |
|---|---|---|
source.kind | "camera" | "camera", "video", "network" (through FFmpeg) or "demo" (simulated fly) |
source.device | "auto" | Camera: "auto", a number from --list-cameras, a device path, or part of the name (choosing a camera) |
source.path | Video file (kind = "video") | |
source.repeat | false | Video: loop at the end |
source.realtime | true | Video: play at the recorded frame rate; false processes as fast as possible |
source.url | Stream URL (kind = "network"), for example rtsp://… | |
source.beat_hz | 0.8 | Simulated fly: how fast its stroke changes, below fps / 2 |
source.width, source.height | 640, 480 | Processing size, 32–8192 each, at most 32 megapixels. Other sizes are scaled to fit without distortion |
source.fps | 30 | Requested camera rate, 1–10000 |
Only the keys of the chosen kind are allowed. A config with kind = "camera"
and a path is an error, so a typo cannot be silently ignored.
Body axis: [head], [tail]
| Key | Default | Meaning |
|---|---|---|
head.x, head.y | 320, 175 | The head end of the body axis (pixels) |
tail.x, tail.y | 320, 330 | The tail end of the body axis (pixels) |
The head and tail must be distinct, and the body axis must not be parallel to the line between the wing hinges.
[tracking]
| Key | Default | Meaning |
|---|---|---|
tracking.asymmetric | false | Edit the wings independently instead of mirroring |
tracking.dark_on_light | true | A dark insect on a light background. false for a bright insect on dark |
tracking.subtract_background | false | Track the difference from the saved background |
tracking.background_path | "rig-a.background.png" | The background image, saved by Save BG |
tracking.angle_bins | 240 | Angular samples per sector, 16–2048 |
tracking.radial_samples | 72 | Radial samples per sector, 4–1024 (bins × samples at most 524,288) |
Parts: [tracking.left], [tracking.right], [tracking.head], [tracking.abdomen]
Each part has the same keys. Here <part> stands for left, right, head or abdomen.
| Key | Default (wings) | Meaning |
|---|---|---|
tracking.<part>.enabled | true (false for head and abdomen) | Track this part |
tracking.<part>.hinge.x, tracking.<part>.hinge.y | left (296, 240), right (344, 240) | The hinge (pixels): where the wing turns, at its base. For the head and abdomen, the pivot |
tracking.<part>.start_deg | left 135, right -85 | Where the sector starts: image degrees, clockwise from image-right |
tracking.<part>.span_deg | 130 | The sector’s angular size, 5–355 |
tracking.<part>.inner_radius | 55 | Inner radius (pixels): just past the body |
tracking.<part>.outer_radius | 185 | Outer radius (pixels): inside the wing blur |
tracking.<part>.method | "wing_blur" (wings), "centroid" (head, abdomen) | "wing_blur" robust, "edge" classic, "centroid". "robust" is accepted for "wing_blur" |
tracking.<part>.primary_edge | "strongest" | Which edge is the angle: "strongest", "toward_head" (leading edge) or "toward_tail" (trailing edge) |
tracking.<part>.threshold | 0.0 | Minimum edge strength, 0–1. 0 reports the strongest edge |
tracking.<part>.max_edges | 2 | Edges reported in angles_rad, 1–8 |
tracking.<part>.spike_width_deg | 5.0 | Robust detector: features narrower than this are ignored, 0–45 |
tracking.<part>.contrast_cap | 0.12 | Robust detector: contrast limit above the background, as a fraction of full brightness |
What these mean, and when to change them: The detectors and Tuning a rig.
[output]
| Key | Default | Meaning |
|---|---|---|
output.zmq_enabled | true | Publish Kinefly-compatible ZMQ |
output.zmq_bind | "tcp://*:9871" | ZMQ publisher address. tcp://127.0.0.1:9871 keeps it on this computer |
output.enabled | true | Send full measurements over UDP |
output.bind | "127.0.0.1:5501" | This rig’s own UDP sending address; every rig needs a different port |
output.target | "127.0.0.1:5601" | Where your UDP receiver listens |
output.jsonl_path | "" | Also write every measurement to this JSONL file. Empty = off. Never overwritten |
[recording]
| Key | Default | Meaning |
|---|---|---|
recording.enabled | false | Record from the start of every run |
recording.directory | "recordings" | Where recording sessions go |
recording.format | "mjpeg" | "mjpeg", "png" or "raw" |
recording.quality | 90 | MJPEG quality, 1–100 |
recording.queue_frames | 32 | Frames that may wait for the disk, 1–256 (at most 256 MiB) |
recording.segment_mb | 1024 | Start a new AVI file at this size, 16–1900 |
See Recording video.
A complete config
The config for the first camera, as shipped, with its comments:
# Rig A: the first camera. UDP 5501 → 5601, ZMQ 9871.
# The GUI saves marker and detector edits back into this file automatically;
# these comments are kept. Run it with: rekkefly --config <this file>
# Every setting is explained in the README ("Configuration reference").
# Name shown in the window title, logs and recording folder names.
instance = "rig-a"
# How often the GUI preview refreshes. Tracking always uses every frame.
preview_fps = 40
# Save GUI edits 300 ms after you stop dragging (and on close).
autosave = true
[source]
# kind: "camera", "video", "network" or "demo" (simulated fly).
kind = "camera"
# device: "auto" = first camera that opens; a number = its position in
# `rekkefly --list-cameras` (0 = first); or a device path such as
# /dev/v4l/by-id/... (Linux, stable across reboots), or part of the camera name.
device = "auto"
# Processing size and requested frame rate. Other camera modes are scaled to fit.
width = 640
height = 480
fps = 30
# Body axis: drag the magenta head dot and cyan tail dot onto the insect.
[head]
x = 320.0
y = 175.0
[tail]
x = 320.0
y = 330.0
[tracking]
# false: the wings mirror each other across the head–tail axis while you edit.
asymmetric = false
# Angular and radial sampling of each sector (more = finer, slower).
angle_bins = 240
radial_samples = 72
# true: dark insect on a light (backlit) background; false: bright insect on dark.
dark_on_light = true
# Track the difference from a saved empty-scene image ("Save BG" in the toolbar).
subtract_background = false
background_path = "rig-a.background.png"
# Wing sectors. Angles are image degrees, clockwise from image-right.
# method: "wing_blur" = robust, ignores legs and antennae (default)
# "edge" = classic strongest edge of the averaged profile
# "centroid" = intensity centroid (used for head/abdomen)
# threshold: 0 reports the strongest edge however faint; raise it to reject noise.
# spike_width_deg: robust mode ignores dark features narrower than this (legs, antennae).
# contrast_cap: robust mode limits contrast so opaque legs cannot outweigh a translucent wing.
[tracking.left]
enabled = true
start_deg = 135.0
span_deg = 130.0
inner_radius = 55.0
outer_radius = 185.0
method = "wing_blur"
threshold = 0.0
max_edges = 2
primary_edge = "strongest"
contrast_cap = 0.12
spike_width_deg = 5.0
[tracking.left.hinge]
x = 296.0
y = 240.0
[tracking.right]
enabled = true
start_deg = -85.0
span_deg = 130.0
inner_radius = 55.0
outer_radius = 185.0
method = "wing_blur"
threshold = 0.0
max_edges = 2
primary_edge = "strongest"
contrast_cap = 0.12
spike_width_deg = 5.0
[tracking.right.hinge]
x = 344.0
y = 240.0
[tracking.head]
enabled = false
start_deg = -125.0
span_deg = 70.0
inner_radius = 12.0
outer_radius = 62.0
method = "centroid"
threshold = 0.0
max_edges = 2
primary_edge = "strongest"
contrast_cap = 0.12
spike_width_deg = 5.0
[tracking.head.hinge]
x = 320.0
y = 205.0
[tracking.abdomen]
enabled = false
start_deg = 55.0
span_deg = 70.0
inner_radius = 15.0
outer_radius = 88.0
method = "centroid"
threshold = 0.0
max_edges = 2
primary_edge = "strongest"
contrast_cap = 0.12
spike_width_deg = 5.0
[tracking.abdomen.hinge]
x = 320.0
y = 265.0
[output]
# Full measurements as JSON over UDP, one datagram per frame.
enabled = true
# This rig's own sending port: every rig needs a different one.
bind = "127.0.0.1:5501"
# Where your receiver listens (python3 examples/receive_udp.py --port 5601).
target = "127.0.0.1:5601"
# Also write every measurement to this JSONL file (relative to this config). Empty = off.
jsonl_path = ""
# Kinefly-compatible ZMQ publisher. Subscribers connect to tcp://<this computer>:9871.
zmq_enabled = true
zmq_bind = "tcp://*:9871"
[recording]
# Start recording as soon as this rig starts (the Record button works any time).
enabled = false
# Folder for recordings, relative to this config.
directory = "recordings"
# "mjpeg" = small (about 10–20× smaller than raw), "png" = lossless, "raw" = lossless and largest.
format = "mjpeg"
# MJPEG quality 1–100; 90 is visually lossless for wing tracking.
quality = 90
# Frames buffered for the disk writer, and the size of each AVI file.
queue_frames = 32
segment_mb = 1024
The other shipped configs are in
configs/:
camera-b.toml (second camera and ports), bogong-moth.toml (the example video),
demo.toml (the simulated fly), network.toml (an RTSP stream) and
rigs.toml (a rig manifest).
Rig manifests
rigs.toml lists rigs to start together; its keys are in
Several rigs at once.