System designExplainer

Read actual exposure per frame when metadata says unsupported

When the metadata query reports no per-frame actual exposure, the value ships with the frame: read chunk data, embedded payload bytes and control readback.

LumaSpec Vision10 min read Share on LinkedIn

On this page 11 sections
  1. 01What an unsupported answer rules out
  2. 02The four channels, in the order to try them
  3. 03Switch the channel on, then prove it
  4. 04Why the honored value differs from the one you set
  5. 05Worked example: one chunk value, one decision
  6. 06Control readback: quick to try, and when it lies
  7. 07When the answer is: take the exposure over
  8. 08Depth heads and the payload-bytes path
  9. 09Decision, per situation
  10. 10Before you order the camera
  11. 11Questions

Auto exposure is on, the part is moving, and you need the exposure the sensor actually honored — not the value you requested yesterday. You ask the per-frame metadata query and it reports the actual-exposure id as unsupported. That answer rules out one delivery channel, not the camera: the value usually still travels with every frame, in an embedded payload line, in a GenICam chunk, or back through the stream's exposure control. This guide shows where to look and in which order, how to prove the number you found is the honored one, and how to turn it into a motion-blur decision with arithmetic you can repeat. The checks apply to GigE area scan cameras, USB3 bodies and the depth heads in the 3D sensors range.

What an unsupported answer rules out

The support flag is per stream and per id. Firmware packs a short list of values into each frame header — frame id and timestamp almost always, exposure and gain only where the silicon delivers them. A depth or infrared head commonly carries the exposure id while the color head of the same device does not, so query each stream on its own and keep two code paths where they disagree.

A false flag does not mean the camera cannot tell you anything. It means this id is absent from the per-frame header, and three other channels remain. Metadata ids are named constants — the exposure one appears as ACTUAL_EXPOSURE on the families that pack it — and one rule holds across stacks: run the support test before the getter, because stacks raise an exception on an unsupported id rather than return a default.

Where the id is supported, the job is easy: read it each frame and cross-check it against gain, as in per-frame exposure and gain: verifying camera metadata. The rest of this guide is for the streams where the flag reads false.

The four channels, in the order to try them

  1. Embedded payload bytes. Depth cameras often pack per-frame values into the first bytes of the image buffer. The layout is a fixed offset table in the vendor's integration note, the API never exposes it, so you parse the field yourself and pin the firmware version the table belongs to.
  2. Chunk data. GigE Vision, USB3 Vision and CoaXPress can append per-frame values to the image payload, and GenICam lists them in the stream module of the feature browser. Enable the exposure chunk once and the value arrives with every grab.
  3. Control readback. The GenICam standard's exposure feature (ExposureTime, in microseconds) reports what the device last applied, and a USB Video Class device exposes an absolute exposure control through the video driver.
  4. Your own loop. Replace auto exposure with a bounded software loop; exposure becomes an input you set, so there is nothing left to read back.

Work the list top to bottom. The first two channels return a true per-frame value, the third returns the last applied setting, and the fourth removes the question. The GenICam capability query walks the enumeration you need for channels two and three.

Switch the channel on, then prove it

GigE Vision bodies expose their feature set through GenICam, so the browser in the vendor's SDK lists exactly which chunks the firmware implements; if an exposure chunk is missing from the list, no call will conjure it. Enable the chunk on the stream module and the value rides in with each image instead of arriving a frame late.

Prove the channel before you build on it: the light-step sweep in the FAQ takes five minutes and separates a live value from a stale buffer. Log every value with its frame time so a change pairs with the right image — the chunk timestamp latch shows how to take the camera's clock at exposure end. If you would rather set exposure live from the control side, the runtime parameter pattern applies unchanged.

Two current 20 MP bodies for the bench check, one on GigE and one on USB3:

Area scan camerasHikrobot MV-CS200-10GC 20 MP Area Scan Camera, GigE, IMX183, Color, BasicMV-CS200-10GC
Sensor format
1"
Lens mount
C-mount
$739.00View part
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
$759.00View part

Why the honored value differs from the one you set

Three mechanisms pull actual exposure away from the request. Quantization: sensors step exposure on an internal clock, so a request of 10,000 µs can be honored as 10,016 µs. The frame-period clamp: exposure cannot exceed the time between frames, so at 60 fps nothing above 16,667 µs is ever honored. Auto exposure: the algorithm re-aims every frame, so the setting you typed is a starting point, not a fact.

frame period (µs) = 1,000,000 / frame rate (fps) blur (px) = part speed (mm/s) × exposure (µs) / (1,000,000 × pixel pitch (mm)) max exposure (µs) for 1 px of blur = 1,000 × pixel pitch (µm) / part speed (mm/s)

When auto exposure drifts into blur territory, cap it rather than replace it: capping the maximum auto exposure time keeps the algorithm and sets the ceiling. When the id is supported but the value looks implausible, the exposure-from-metadata walkthrough shows the retrieval under auto exposure and the cross-check against the image.

Worked example: one chunk value, one decision

A 4,000-pixel camera watches a conveyor through a 120 mm field of view, so pixel pitch is 120 / 4,000 = 0.03 mm. Part speed is 150 mm/s. The exposure chunk returns 2,777 µs — a value nobody would type by hand, which is the tell that auto exposure chose it.

Blur = 150 mm/s × 2,777 µs / 1,000,000 = 0.417 mm, which is 0.417 / 0.03 = 13.9 px of smear. A fourteen-pixel smear fails any edge check, so the number drives the fix instead of a debate.

Budget one pixel: max exposure = 1,000 × 30 µm / 150 mm/s = 200 µs. Cap auto exposure at 200 µs, recover brightness with light or gain, and re-read the chunk on the next runs — the value should sit at or just under 200 µs. The frame-period clamp is nowhere near binding: 1,000,000 / 60 = 16,667 µs, so 200 µs spends about 1.2% of the frame time.

Decision: with the chunk live, keep auto exposure capped at 200 µs and log the honored value with every frame id.

Control readback: quick to try, and when it lies

Channel three is the fastest to test, so start there when the chunk list comes up empty. Under manual exposure the exposure feature reads back the honored value, quantization aside — good enough for a fixed station where the setting never moves. Under auto exposure, some stacks report the algorithm's target instead of the value each frame used, and on multi-head devices the depth stream can update the value while the color stream never does. Treat control readback as a sanity check, not as a per-frame log.

UVC devices route the same information through the video driver's absolute exposure control; read it through the driver, not the pixel stream. The unit belongs to the driver, not to GenICam — steps of 100 µs are typical on the Linux USB video driver — so convert once at the boundary and keep microseconds everywhere downstream.

When the answer is: take the exposure over

If every channel comes up empty — no chunk in the browser, no payload layout in the integration note, a control register that will not track auto exposure — write the loop. A bounded software auto-exposure routine adjusts exposure from measured brightness, so the value you computed is the value the sensor honors and the readback question disappears. That is usually why per-frame exposure mattered in the first place: the built-in algorithm hunts under your lighting, so taking over fixes both problems at once. The bounded software auto-exposure loop gives the pattern: measure, step, clamp, repeat.

Cost: wiring the loop is about an afternoon against a day of payload parsing, and it ends the dependency on whatever the firmware chooses to expose. On stations where the factory auto exposure hunts, we spec the loop first.

Depth heads and the payload-bytes path

Depth, stereo and structured-light heads are a common place for the exposure id to read false across every stream at once, and where the payload-bytes channel earns its keep: the leading bytes of each frame can carry the values, with the offset table in the integration note. Enable whatever the stream module offers first, parse bytes only when the table exists, and re-check the table whenever the firmware changes.

For stations that need this class of camera from the start, the 3D sensors category carries the stereo, structured-light and laser-profiler families; a current projected structured-light camera:

3D sensorsHikrobot MV-DPS200P-02 Projected structured-light 3D cameraMV-DPS200P-02
Type
Stereo / structured light
$8,829.00 · quotedView and quote

Decision, per situation

Situation Channel What you get
Exposure id supported on the stream Metadata getter Honored value per frame, zero setup
GenICam chunk listed in the browser Chunk on the stream Honored value with every grab
Depth head with a payload layout table Embedded bytes, parsed Honored value; pin the firmware
Manual exposure, fixed station Control readback Last applied value, quantization aside
No channel works, or auto exposure hunts Bounded software loop Value known by construction

Rows two and three take about a day each; row five is also about a day and removes the dependency entirely. Rows one and four are minutes. Commit in this order and the exposure question closes with a number you can defend.

Before you order the camera

Filter for transports that carry chunk cleanly — GigE, USB3, CoaXPress — in the camera finder, or wire the whole chain in the camera configurator. If a specific family's metadata map is the deciding factor, ask through the contact page before you commit; every order includes free expert support. More stream-side diagnostics sit on the systems topic page.

Questions

Why does the support query return false for exposure on one stream and true on another?

The flag is set per stream by the camera firmware, not by your code: a depth or infrared head may pack an exposure value into every frame while the color head of the same device has no such field. Query each stream separately and keep two code paths. On some devices the depth id updates live while the color id never does, which matches the per-stream result you see.

What unit does the exposure value come back in?

GenICam defines its exposure feature in microseconds, and chunk payloads follow it, so 2,777 means 2.777 ms. UVC readback arrives in the driver's unit: the Linux USB video driver reports absolute exposure in steps of 100 µs, so a readback of 27 means 2.7 ms. Convert once at the driver boundary and keep microseconds everywhere else in the pipeline.

Can I recover the exposure afterwards from saved image files?

Only if the grab code copies it out when the frame arrives. Standard image encoders keep pixels and drop the payload chunk, so a PNG or JPEG written straight from the buffer carries no exposure at all. Log value plus frame id or timestamp to a side file at capture time; the chunk timestamp mechanism shows how to latch the camera-side time so the pairing stays exact.

Does manual exposure still need a per-frame readback?

Under manual exposure the value you set is the value the sensor honors, within clock quantization — a request of 5,000 µs can land as 5,008 µs. For a fixed station that error rarely matters, so the readback is optional there. The moment auto exposure is on, or the frame rate clamps exposure to the frame period, read the honored value per frame instead.

How do I prove the chunk value is the honored exposure?

Fix the aperture, aim at an evenly lit target and halve the light in a calibrated step. Under auto exposure the readback should double within the sensor's step size; under manual exposure it should hold at your commanded value. If the number freezes while the image brightens, you are reading a stale buffer or the wrong chunk id — re-enable the chunk and grab a fresh frame.