System designHow-to

Camera parameter set and get in a capture loop safely

Why set and get calls on a GenICam camera are synchronous but not frame-accurate, and how to write exposure and gain per trigger without crashes.

LumaSpec Vision9 min read Share on LinkedIn

On this page 8 sections
  1. 01What set and get really do
  2. 02Why the crash appears after splitting the calls
  3. 03Doing it right: a typed, threaded pattern
  4. 04A worked example: alternating exposure per trigger
  5. 05Where the loop runs
  6. 06Checks before you trust the loop
  7. 07When the usual answer is wrong
  8. 08Questions

Setting exposure, gain and auto flags on a camera from inside a running capture loop is a common requirement: per-part recipes, alternating light schemes, or a control loop that reacts to brightness. It is also a reliable way to introduce random segmentation faults if the calls are mistyped or made from the wrong thread.

The short answer to the synchronous question: the calls are synchronous, the frames are not. A setter writes to the device before it returns, and a getter reads from the device before returning. A get immediately after a set returns the new value. But the frame the sensor is exposing at that moment was started with the old parameters, so the next image you receive may still look like the old setting. This how-to shows how to structure set and get calls so they are frame-accurate, type-safe and thread-safe, and how to diagnose the crash that appears after you refactor the calls. For a worked discussion of reading exposure and gain back out of image metadata, see per-frame exposure and gain: verifying camera metadata.

What set and get really do

A parameter write to a GenICam camera goes through the device control channel. The call sequence is: your code calls set, the value is validated against the feature's range, the register is written, and only then does the call return. A get follows the same path in reverse. There is no deferred application at the API level and no internal queue where your new value waits.

The delay that confuses people is in the sensor, not the API:

  1. The frame currently being exposed keeps the exposure time it was started with.

  2. A frame already read out and queued keeps its own parameters.

  3. The next frame started after the write returns uses the new value.

So "set then get" always returns the new value, but "set then look at the next image" may show the old one. If you need to know which image used which setting, match on frame ID, not on wall-clock order.

frames_with_old_setting ≥ ceil(exposure_time / frame_period)

This is an estimate: at long exposure times relative to the frame period, more than one delivered frame can carry the old setting.

Why the crash appears after splitting the calls

A frequent report runs like this: a combined call setting several parameters at once works, and after splitting it into one call per parameter, a segmentation fault appears at random intervals, typically inside a memory copy in the frame queue thread. Two causes account for most of these.

Wrong variable types on get. Integer features on GenICam cameras are 64-bit integers. If your destination variables are 32-bit ints, a get-style call that writes 8 bytes per feature overflows each destination by 4 bytes and corrupts the stack around it. The corruption then detonates later, in unrelated code — which is why the backtrace points at a memcpy, not at your parameter code. Use gint64 (or int64_t) for every integer feature, including values you expect to be small such as an auto-mode enumeration.

Buffer lifetime races. Splitting one call into several widens the time window in which the streaming thread delivers frames while your code is still running. If your image callback or appsink handler holds a pointer into a buffer that the pipeline reuses, the extra delay turns a latent bug into a crash. Copy or reference the buffer before anything slow, and never run parameter writes from inside the frame callback. The pattern of queue stalls and recovery faults around heavy capture loops is covered in camera acquisition stalls under load: isolate recovery faults.

Doing it right: a typed, threaded pattern

You need a camera, a lens if the camera has no integrated optics, and a place to run the loop. A USB3 model such as LS-CMR-0166 or a GigE model such as LS-CMR-0053 works; the pattern is interface-independent.

  1. Declare every integer parameter variable as a 64-bit signed integer. In C that is gint64 or int64_t; do not use int, even for enumerations.

  2. Write all related parameters in one combined call where your API supports it. One call with four name-value pairs is atomic from your code's point of view and minimises the windows between writes.

  3. Read values back once, after the write, outside the fast loop. Verify that what came back matches what you sent. If a feature name is refused, the naming or registration is wrong — diagnosing that is its own task, covered in GenICam node not existing: diagnose feature access errors.

  4. Never call set or get from the image callback thread. Queue the desired parameters in a small thread-safe structure and let a control thread apply them. A register write can take milliseconds; the callback must return as fast as it can.

  5. Copy image data out of pipeline-owned buffers before any processing, saving or display work. If your framework offers a buffer copy or reference call, use it; the copy in the backtrace is almost always the victim, not the culprit.

  6. Cache the last applied value of each parameter and write only on change. Rewriting identical values every trigger adds register traffic for no benefit and makes genuine changes harder to trace.

  7. Log the frame ID with each parameter change. When an image looks wrong later, you can prove which setting produced it instead of guessing.

A worked example: alternating exposure per trigger

Suppose a cell inspects parts with a bright and a dark feature, and you alternate exposure between 2,000 µs and 8,000 µs on successive triggers, with gain fixed.

  • Trigger N: write 2,000 µs, trigger the frame, receive it.
  • Trigger N+1: write 8,000 µs, trigger the frame, receive it.

If your frame period is, say, 100 ms and each exposure is well under it, the write completes before the next trigger, so each frame matches its intended value — the estimate above gives 1 frame of old setting at most, and you consume it before the next trigger. The dangerous configuration is a short frame period with the write happening on the callback thread: the write delays the callback, buffers back up, and the pipeline either drops frames or crashes. Keep the write on the control thread, triggered before the hardware trigger pulse, and the timing stays deterministic.

For brightness-driven adjustments instead of recipe switching, the feedback-loop pitfalls and limits are covered in automatic iris, exposure and gain control in machine vision.

Area scan cameras12 MP USB3 area scan camera, IMX226, 1/1.7" rolling shutter, 30 fps, 4000 × 3000 resolution (LS-CMR-0166)LS-CMR-0166
Sensor format
1/1.7"
Interface
USB3
Resolution
12 MP
Shutter
Rolling
$560.00View partBuild a system with it

Where the loop runs

The host matters as much as the camera. A vision controller with multiple LAN ports and built-in light channels keeps camera traffic, light strobing and PLC communication on separate interfaces; an example is the MV-VC3301H-128G66 in the vision controllers category. On embedded ARM boards, capture crashes can also stem from the platform's video-interface stack rather than your code — that class of platform-level fault is covered in ARM64 machine vision acquisition: check binary compatibility.

Vision controllersHikrobot MV-VC3301H-128G66 I3-8100, 8GB+128G SSD, No PoE, PCIe expansion supported, Incl. VM6200Pro licenseMV-VC3301H-128G66
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
Light outputs
4 built-in channels
Memory
8 GB
$2,419.00View partBuild a system with it

If you are still choosing the camera, the area scan camera finder filters by interface and resolution, and the system configurator walks camera, lens and light in one pass.

Checks before you trust the loop

  • Every integer parameter variable is a 64-bit type, checked by reading the compiler headers, not by eyeball.
  • The readback after each write matches the written value, logged once at startup and after any change.
  • Parameter writes happen on a control thread, demonstrably never inside the frame callback (assert it in debug builds).
  • Image data is copied or referenced before processing, and the copy target is sized from the actual frame dimensions.
  • Frame IDs are logged with parameter changes for at least one full production shift.
  • The loop runs at maximum production rate for an hour without a dropped frame or a growing queue.

When the usual answer is wrong

Two cases break the "set is synchronous" mental model in practice. First, auto modes: if ExposureAuto is still on, your manual ExposureTimeRaw write may be accepted and then immediately overridden by the camera's auto algorithm, so the readback matches but the images do not. Always write the auto flag off before writing the raw value, and check for writes that revert — exposure resets during acquisition: find the cause covers that symptom. Second, multi-camera setups: synchronous per-camera writes serialise across cameras on a shared interface, so a loop that is fine with one GigE camera can become slow with four. Batch the writes, or stagger them across trigger cycles.

If a crash survives all of the above, take the backtrace with a debugger before changing anything else: the faulting thread's name usually tells you whether the problem is in the streaming path or in your parameter code. And if you want a second pair of eyes on the design, contact us — expert support comes with every order.

Questions

Are camera parameter set and get calls synchronous?

At the API level, yes. A setter writes the value to the camera before it returns, and a getter queries the camera before returning its value. A get immediately after a set returns the new value. The subtlety is frame timing: the frame already being exposed still uses the old exposure or gain, so the image you receive next may not yet reflect the write. Match parameters to images by frame ID, not by call order.

Why does a segmentation fault appear after splitting set and get calls?

Splitting one combined call into several separate calls widens the time window during which the streaming thread runs, so a latent race or a type bug surfaces. The two classic causes are wrong variable types on get — integer GenICam features are 64-bit, so an int destination overflows into neighbouring stack memory — and buffer reuse, where the callback hands back a buffer the pipeline recycles. Fix the types first, then copy or ref the buffer before any slow work.

What type should I use for integer camera features?

Use a 64-bit signed integer type, for example gint64 in C or int64_t in C++. Exposure time raw, gain raw and most enumerations are exposed as 64-bit integers by GenICam cameras. Passing a 32-bit int to a get-style call that writes 8 bytes causes memory corruption that shows up as a crash somewhere else entirely, often in a memcpy inside the frame queue.

Should I write exposure and gain on every trigger?

Only when the value actually changes. Writing identical values per trigger adds register traffic on the camera and load on the host for no benefit. Cache the last applied value, compare, and write only on change. Also keep writes off the image callback thread; queue the desired values and apply them from a control thread, so a slow register write never blocks frame delivery.

How do I verify a parameter write actually took effect?

Read the feature back once after writing it, outside the fast loop, and check that the returned value matches. Then confirm the effect on images: capture a frame after the write, measure its mean intensity, and check it moved in the expected direction. If you need per-frame proof, log the frame ID alongside the applied value so you can match images to settings later, as covered in verifying per-frame metadata.