Cameras & sensorsHow-to

Gain parameter type: float or integer in one GUI slider

One slider for Gain whatever the parameter type: query the node at init, bind the float Gain or GainAbs, or the integer GainRaw, and step by its increment.

LumaSpec Vision9 min read Share on LinkedIn

On this page 9 sections
  1. 01Why does Gain change type between cameras?
  2. 02Which node should the code try first: Gain, GainAbs or GainRaw?
  3. 03How do you query the parameter type at initialization?
  4. 04How do you build one slider that serves both types?
  5. 05How do you map the node range onto slider ticks?
  6. 06Why does the slider snap back after you drag it?
  7. 07What breaks if you hardcode one type everywhere?
  8. 08What should you test before shipping the GUI?
  9. 09Questions

The same feature arrives under three names. Which one your camera answers depends on the version of the GenICam Standard Features Naming Convention (SFNC) it implements: gain is a float node called Gain, a float node called GainAbs, or an integer node called GainRaw. A GUI that assumes one of them works perfectly until the day someone swaps cameras. This guide shows you how to detect the parameter type once at initialization, bind a single dual-mode slider to whichever node exists, and step it by the node's own increment. The code sketches are C#-shaped; the init order and the range math are identical in any language.

Why does Gain change type between cameras?

Because the SFNC renamed the feature between versions: SFNC 2.x defines Gain as a float, while devices built on SFNC 1.x expose GainAbs as a float or GainRaw as an integer.

The SFNC standardizes the names and behavior of common features — exposure time, gain, acquisition frame rate — so software written against one version still addresses the camera correctly. The catch is the word version: a camera bought this year and one bought five years ago, both GigE Vision, can answer the question of gain with a different name and a different type.

Node SFNC family Parameter type Unit
Gain 2.x Float dB
GainAbs 1.x Float dB
GainRaw 1.x Integer device-specific counts

The float nodes carry decibels; one current GigE Vision device documents a float Gain from 0 dB to 18 dB. GainRaw carries unitless counts defined by that camera's analog front end, which is why it must be displayed as counts and never dressed up as dB.

Which node should the code try first: Gain, GainAbs or GainRaw?

Try Gain first, then GainAbs, then GainRaw: this prefers the newest convention, keeps the two float nodes — both in decibels — ahead of raw counts, and stops at the first name the device actually reports.

Float first because decibels compare across camera models: 6 dB means 6 dB everywhere. Counts do not — 40 on one camera is not 40 on the next — so an integer node earns the label counts and nothing more.

A shipped C# Live View sample solves exactly this. Its older layout used separate user controls per type, FloatSliderUserControl.cs and IntSliderUserControl.cs, and picked one per camera. The current layout adds DualSliderUserControl.cs, a single control that accepts a float or an integer parameter, and binds the right one during initialization from MainForm.cs, inside the deviceListView_SelectedIndexChanged() event handler that fires whenever the operator selects a device.

If none of the three names exists, disable the slider and log the three names you probed. Absence is a device fact, not a crash.

How do you query the parameter type at initialization?

Open the node map before the GUI is shown and ask three things about each candidate name: does the node exist, is its interface float or integer, and what are its minimum, maximum and increment.

In GenApi terms every feature arrives through a typed interface — IFloat or IInteger — and both publish the range and the step. Reading them at init is the same query-first discipline as querying the option range before setting exposure or gain, and the wider pattern is covered in how to query camera capabilities with GenICam.

// Illustrative C#. The plain names are this example's own variables;
// Gain, GainAbs and GainRaw are the SFNC node names as reported.
string gainNode = "";      // "Gain", "GainAbs" or "GainRaw", filled at init
bool gainIsFloat = false;  // true when the interface is float
double gainMin = 0.0;      // dB for float nodes, counts for GainRaw
double gainMax = 0.0;
double gainStep = 1.0;     // read from the node; never assume 1 on a float

Re-run the whole probe every time a device is selected, not once per application start. The same detect-then-set order in Python is shown in setting camera exposure time through a GenICam API in Python.

How do you build one slider that serves both types?

Build one user control that owns two child widgets — a track bar with a dB label for floats, a track bar with a counts label for integers — and shows only the one that was bound at init.

  1. Set GainAuto to Off. The SFNC defines Off, Once and Continuous; while it is not Off, the camera writes gain itself and your slider is a spectator. Enumerations go by symbolic name or mapped integer, as in setting a GenICam enumeration by integer value.
  2. Probe in the order from the previous section; store the node name and the type flag.
  3. Read minimum, maximum and increment from the node you found.
  4. Compute the tick count and set the track bar bounds; make one keyboard step equal one increment.
  5. Wire the track bar's value-changed event to a write that matches the type: a double for the float node, whole counts for the integer node.
  6. Wire the reverse path: the API's parameter-changed callback where one exists, otherwise a re-read when the control regains focus.
  7. On device change, unbind and repeat from step 1 — which is exactly what the sample's deviceListView_SelectedIndexChanged() handler does.

Gain sits next to exposure and white balance on most tuning screens; the live-tuning side of that screen is covered in runtime camera parameter control: exposure and white balance live.

How do you map the node range onto slider ticks?

Divide the span by the node's increment: a float Gain spanning 0.0 dB to 18.0 dB in 0.1 dB steps needs (18.0 - 0.0) / 0.1 = 180 ticks, and an integer GainRaw spanning 0 to 63 needs 63 - 0 = 63 ticks.

ticks = round((max - min) / step) value = min + position x step display error <= step / 2

Camera A, a float device, reports at init: minimum 0.0 dB, maximum 18.0 dB, increment 0.1 dB. Ticks = (18.0 - 0.0) / 0.1 = 180, so the track bar runs 0 to 180. Drag to position 47 and the written value is 0.0 + 47 x 0.1 = 4.7 dB; the worst rounding error is half a step, 0.05 dB.

Camera B, an integer device, reports minimum 0, maximum 63, increment 1, giving 63 ticks. The same position 47 now means 47 counts — a different physical gain on a different analog front end. Same control, no code change between the two cameras.

Always snap the written value to the node's increment so the read-back equals what you display.

Why does the slider snap back after you drag it?

Because GainAuto is not Off: in Once mode the camera adjusts gain until it converges and then stops, and in Continuous mode it keeps overwriting your value, so the next read drags the slider back.

The fix is step 1 of the build sequence, applied before the first bind, not after the first complaint. Two related habits: raise exposure before gain when the image is dark, because gain multiplies noise with signal — the trade is worked through in manual exposure darker than auto exposure: why AE beats your gain — and when the line is running, change camera gain at runtime without stopping the pipeline keeps the stream alive while you do it.

What breaks if you hardcode one type everywhere?

Three failures, most frequent first: a missing-node error at startup when the assumed name does not exist, a wrong-type exception when a float accessor meets an integer node, and — worst — a silent wrong unit when raw counts are displayed as decibels.

The first is diagnosed in GenICam node not existing: diagnose feature access errors; its feature-not-supported cousin is covered in camera feature not supported error: query capabilities first. The third failure throws nothing: an operator simply reads 18 as though it were dB when it is 18 counts. And an integer node only holds whole counts, so a value like 4.7 can never land exactly — the GUI must not offer decimals on a raw node.

What should you test before shipping the GUI?

Rebind across two camera generations in one session, force a device that has none of the three nodes, and drag to both extremes while reading the value back from the node itself — those three tests catch every failure mode above.

  • Swap cameras without restarting the app; slider, range and unit label must follow.
  • Type a value at the keyboard as well as dragging it; both paths must snap to the increment.
  • Set GainAuto to Continuous from another tool, then confirm your GUI re-reads instead of freezing the old number.
  • Write the maximum, then the minimum, and read both back.
  • Unplug mid-drag; the control must disable, not throw.

The test that proves the mapping, run once per connected camera:

long ticks = (long)Math.Round((gainMax - gainMin) / gainStep);
// camera A, float Gain 0.0-18.0 dB, step 0.1 dB -> ticks == 180
// camera B, integer GainRaw 0-63, step 1 -> ticks == 63
Debug.Assert(ticks == 180 || ticks == 63);

Any two cameras from the area scan cameras range make a realistic swap pair. The LS-CMR-0053 is a 12 MP GigE camera at 9 fps and the LS-CMR-0166 is a 12 MP USB3 camera at 30 fps, both on the same 1/1.7" sensor — so the transport differs and little else does.

Area scan cameras12 MP GigE area scan camera, IMX226, 1/1.7" rolling shutter, 9 fps (LS-CMR-0053)LS-CMR-0053
Sensor format
1/1.7"
Lens mount
C-mount
$560.00View part
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
$560.00View part

For the stranger test, connect a camera the GUI has never seen — a 20 MP USB3 model is a good one — and check that only the range and the label change.

Area scan camerasHikrobot MV-CS200-10UM 20 MP Area Scan Camera, USB3.0, IMX183, 2nd Gen., MonoMV-CS200-10UM
Sensor format
1"
Lens mount
C-mount
Interface
USB3
Resolution
16-25 MP
$759.00View partBuild a system with it

When the GUI is solved and the camera choice is not, the camera finder filters by interface, sensor format and resolution, and the configurator starts at the camera step.

CamerasArea scan cameras

GigE, USB3, 10GigE and CoaXPress

1,287 models · from $149.00

Smart cameras that inspect on the device are configured through their own tooling; the dual slider is for cameras that present a GenICam node map, so browse the smart cameras range only when the device exposes one. If a camera in your fleet answers to none of the three names, send the model over the contact page and we will map its gain node before you write code around it.

Questions

Can GainRaw counts be converted to decibels?

Not portably. GainRaw is a device-specific integer: the counts-to-decibel curve is set by that camera's analog design, and the SFNC defines no conversion. Display counts as counts. If the interface needs decibels, use the float node (Gain or GainAbs); when a camera offers only GainRaw, a lookup table is legitimate only if the camera's own documentation publishes the mapping.

Is one dual-mode control better than two sliders side by side?

One visible control, every time. Two sliders invite an operator to drag the one that is not bound, and recipes saved against the wrong widget fail silently on the next camera. Keep both child widgets inside the user control if the toolkit requires it, but show exactly one track bar with one unit label, chosen at init.

Does exposure time have the same float-or-integer split?

Yes, the pattern repeats one feature over. Older SFNC devices expose ExposureTimeAbs as a float or ExposureTimeRaw as an integer; newer ones expose ExposureTime, a float in microseconds. The same probe-then-bind initialization covers it, with the unit label switching between microseconds and counts.

What should the GUI do when a camera reports none of the three gain nodes?

Disable the control and log the three names that were probed. A missing feature is a property of the device, and the correct response is a grayed-out slider plus one log line an integrator can read, not an exception that takes the screen down. Compact sensors sometimes fix gain internally; the GUI should say so and stay out of the way.

How often should the GUI re-read the gain node?

At init, on device change, and whenever the camera can change the value on its own: while GainAuto is Once or Continuous, poll on a 200-500 ms timer or subscribe to the parameter-changed callback. With GainAuto off, one read after each user write is enough to confirm the value landed on a valid step.