System designExplainer

Software triggered image capture from a GUI button

Build software triggered image capture around a GUI button, with fresh-frame checks, safe buffer ownership, responsive workers and correct file saving.

LumaSpec Vision11 min read Share on LinkedIn

On this page 10 sections
  1. 01Decide what the button promises
  2. 02Establish the acquisition interface and capabilities
  3. 03Follow the capture sequence in the correct order
  4. 04Keep acquisition and saving away from the GUI thread
  5. 05Prove that the image follows the request
  6. 06Copy and save the actual image representation
  7. 07Budget memory and time with a worked example
  8. 08Choose hardware against the acquisition contract
  9. 09Verify the complete path before release
  10. 10Questions

A capture button looks simple, but it must coordinate camera settings, exposure, image transfer, memory ownership and file writing. Reading the next available image is not necessarily the same as exposing an image after the button press. This explanation is for developers adding still-image capture to a desktop interface. You will learn how to build a request-driven acquisition sequence, keep the interface responsive, and verify that the saved image belongs to the accepted request.

Decide what the button promises

Define the button's contract before choosing an acquisition API. These operations have different meanings:

Button behavior What happens What you can promise
Save preview Copy the latest displayed frame The saved image matches a recent preview frame
Fetch next buffer Return the next completed image in the queue An image is delivered, possibly from an earlier exposure
Software-triggered capture Request an exposure after accepting the button press A new exposure follows the request, subject to camera support and correct configuration

If the application needs a newly exposed image, use software triggering where the camera and acquisition software support it. Do not describe a preview snapshot as a new exposure.

A software trigger is not a deterministic motion-synchronization signal. Operating-system scheduling, command transport and camera readiness introduce variable delay. Use an appropriate hardware-triggered design when exposure must coincide precisely with moving machinery. The separate explanation of external pulses and camera frame rate covers that timing problem.

Establish the acquisition interface and capabilities

Start with a documented camera SDK or a compatible GenTL acquisition stack. GenICam provides standardized feature access, while GenTL concerns discovery, device access and image transport. Neither means every camera exposes identical features or uses identical application calls.

Discovery should lead to opening a specific device, preferably using its stable identity rather than its position in a discovery list. Opening the first device becomes unreliable when another camera is connected.

Before enabling the capture button, check that you can:

  • Open the selected camera and its image stream.
  • Read the active image dimensions and pixel format.
  • Configure an appropriate acquisition mode.
  • Select software triggering for the required exposure event.
  • Execute the trigger command when the camera is ready.
  • Receive a completed image and inspect its status.

For cameras exposing the usual feature names, this can involve TriggerSelector, TriggerMode, TriggerSource and TriggerSoftware. A commonly used selector is FrameStart, but its presence and meaning must be checked in the device documentation.

Do not substitute guessed names when a feature is absent. Features can also become unavailable or read-only in particular acquisition states. Follow the checks in diagnosing unavailable GenICam features rather than treating every access failure as a disconnected camera.

For the host software and transport prerequisites, use the GigE Vision software compatibility checks. Install drivers and acquisition components only through the manufacturer or its authorized distribution channels.

Follow the capture sequence in the correct order

Keep the camera open across captures when the application design permits it. Reopening on every click adds delay and creates more opportunities for configuration differences.

  1. Open and identify the device. Record its identity and obtain the documented stream and feature interfaces.
  2. Configure while in the required stopped state. Set image dimensions, pixel format, exposure and gain deliberately. Configure acquisition and software triggering using supported features.
  3. Prepare receive buffers and start acquisition. Follow the SDK's ordering requirements so the transport can receive the resulting image.
  4. Confirm readiness. Use a documented readiness indication where available. Do not assume that returning from a start call means a trigger can already be accepted.
  5. Accept one capture request. Assign an application request identifier and record the host's monotonic time.
  6. Issue the software trigger. Execute the documented command once for that accepted request.
  7. Fetch a completed buffer with a finite timeout. Check completion status, payload type and image metadata before accessing pixels.
  8. Copy the image into application-owned memory. Preserve the image data and metadata needed by the save operation.
  9. Release or requeue the transport buffer. Use the SDK's required release mechanism, including on error paths.
  10. Save and report the result. Report success only after the encoder and file-writing operations complete successfully.

An acquisition mode that supports repeated triggered frames can avoid starting and stopping for every click. The exact mode and stream-start sequence remain device-dependent.

The camera settings reset guide is useful when repeatable startup configuration matters. A documented configuration baseline is preferable to relying on settings left by a previous application.

Keep acquisition and saving away from the GUI thread

The GUI thread should accept input, update controls and display results. It should not wait for camera buffers or encode large images.

A simple design uses one acquisition worker that owns the camera session. The GUI sends capture requests to that worker through a thread-safe queue. Results return through the GUI framework's supported event or signal mechanism.

Component Responsibility Avoid
GUI thread Accept a request, show progress, display results Blocking acquisition calls or direct widget updates from workers
Acquisition worker Configure, trigger, fetch, copy and release Multiple threads issuing commands to the same session without documented coordination
Save operation Encode owned pixels, write files, report errors Holding a borrowed transport buffer during slow disk operations

For occasional still images, saving can remain in the acquisition worker after the transport buffer is released. A separate saving worker becomes useful when encoding or storage latency would otherwise delay subsequent requests.

Use a small state model: Disconnected, Ready, Capturing, Saving and Fault. Disable capture while a request is pending unless the application explicitly supports a bounded request queue.

The following is architectural pseudocode, not an SDK-specific example:

on_capture_button:
    if state is not Ready:
        reject request with a clear status
    else:
        state = Capturing
        send request_id to acquisition worker

in_acquisition_worker:
    wait for documented trigger readiness
    execute software trigger
    fetch completed buffer with finite timeout
    try:
        validate completion and image metadata
        owned_image = copy image and required metadata
    finally:
        release fetched buffer through the SDK
    save owned_image using a compatible encoder
    post success or failure to GUI

Production code also needs exception handling around readiness, triggering, fetching, copying and saving. Release only resources that were actually acquired. On shutdown, stop accepting requests, finish or cancel pending work through documented APIs, then close the stream and device.

Prove that the image follows the request

A new application request identifier does not establish when a camera exposed an image. Associate the request with camera evidence and a controlled acquisition state.

For a simple single-request design, establish an empty receive queue before accepting requests, enable only the intended software-trigger source, and allow no other component to trigger the camera. Any initial queue cleanup must occur through documented acquisition operations before accepting a request.

Do not continuously discard buffers after issuing the trigger. That can discard the requested image itself.

For each request, record:

  • Application request identifier.
  • Host monotonic time when the request was accepted.
  • Host times before and after the trigger command.
  • Frame identifier and camera timestamp, where available.
  • Buffer completion status and host receive time.
  • Output filename and save-completion status.

Frame identifiers can reveal duplicates or gaps, but increasing identifiers alone do not prove freshness. Camera timestamps may use a different clock from the host. Do not directly subtract them from host timestamps without a documented clock relationship.

For a bench test, place a clearly changing counter or display in view. Change its visible state before pressing capture, then verify that the saved image contains the new state. Repeat after idle periods and after an intentionally slow save. This tests the application path, although it does not measure precise exposure latency.

The guide to verifying per-frame camera metadata explains how metadata can support image-level checks. Treat metadata as evidence to interpret, not as a substitute for controlling the acquisition sequence.

Copy and save the actual image representation

An acquisition buffer is usually borrowed memory. After it is released or requeued, the transport may overwrite it with another frame. A GUI image object or array view can still point to that memory even though its variable remains valid.

Create an independent copy before releasing the buffer. Copying an object reference or creating another view is not sufficient. Use the SDK's documented conversion or copying facility, or verify that your array operation allocates independent storage.

Also distinguish image pixels from the entire payload. A payload can contain row padding, chunk metadata or other components. Use the reported image layout rather than assuming that payload length equals width multiplied by height.

Check these properties before encoding:

  • Width, height and row stride.
  • Component count and channel order.
  • Pixel format, meaningful bit depth and storage width.
  • Packed versus unpacked representation.
  • Bayer pattern or other required color interpretation.
  • Whether metadata or additional components accompany the image.

A Bayer image needs an appropriate conversion for normal color display. Packed higher-bit-depth pixels need unpacking or a compatible writer. A preview conversion may also reduce precision, so do not save the displayed preview when measurement data must retain its original values.

Choose a lossless format supported by the encoder for the required image representation. Verify the saved file by reopening it and checking dimensions, data type and representative pixel values. If retaining a raw payload, store the format and layout metadata needed to decode it later.

Budget memory and time with a worked example

Consider a hypothetical monochrome image containing 1920 × 1200 pixels, stored as one byte per pixel without row padding. These are application assumptions, not specifications for any listed camera.

image bytes = width × height × stored bytes per pixel image bytes = 1920 × 1200 × 1 = 2,304,000 bytes two owned copies = 2 × 2,304,000 = 4,608,000 bytes

That is approximately 2.30 MB per image, or 4.61 MB for two owned copies, using decimal megabytes. Transport buffers, encoder workspaces and GUI display copies consume additional memory. Packed formats and padded rows require different calculations.

Suppose measured request stages take 20 ms for exposure, 15 ms for subsequent readout and delivery, 5 ms for copying and conversion, and 30 ms for saving. In a serial implementation:

request time = exposure + delivery + conversion + saving request time = 20 + 15 + 5 + 30 = 70 ms serial request rate estimate = 1000 / 70 ≈ 14 requests per second

This is an illustrative budget, not a camera frame-rate claim. Stages can overlap in other architectures, and storage delays can vary substantially.

Set separate deadlines for receiving an image and completing the whole request. The receive timeout must accommodate exposure, readout, transport and scheduling variation. The overall deadline must also account for conversion and saving. Base both on measurements under expected operating conditions, with a justified margin.

A queue also needs a limit. If accepted requests exceed completed requests by 5 per second for 10 seconds, the backlog grows by 50 requests. For a manual capture interface, rejecting another click while busy is often clearer than silently accumulating work.

Choose hardware against the acquisition contract

Browse area scan cameras when you want host-controlled acquisition and image processing. Use the camera finder to narrow interface, shutter, image format and mounting requirements before checking software support.

The LS-CMR-0395 is a monochrome GigE area scan camera with a global shutter.

Area scan camerasGigE area scan camera, GE series with CMOS sensor, 1.3 MP, GigE, Mono, 4μm pixels (LS-CMR-0395)LS-CMR-0395
Sensor format
1/2.7"
Interface
GigE
Resolution
Up to 3 MP
Shutter
Global
$299.00View partBuild a system with it

The MV-CU020-90GC is a color GigE area scan camera with a global shutter.

Area scan camerasHikrobot MV-CU020-90GC 2MP Area Scan Camera, GigE, GMAX4002, ColorMV-CU020-90GC
Sensor format
1/1.7"
Interface
GigE
Resolution
Up to 3 MP
Shutter
Global
$309.00View partBuild a system with it

These catalog attributes do not establish a particular trigger command, SDK binding or image-saving workflow. Confirm software triggering, readiness behavior, supported pixel formats and host API compatibility in the selected device's documentation before ordering.

Consider smart cameras and vision sensors when inspection should run on the device. A host capture button may then request an inspection result rather than retrieve a full image. Verify image retrieval and triggering independently; on-device processing does not automatically imply the host interface required here.

If your task is only to save what an operator already sees, a preview snapshot may be the simpler correct solution. If exposure must align with fast motion, a GUI software trigger is the wrong timing source.

Verify the complete path before release

Use this acceptance checklist with the actual application, selected camera and intended storage location:

  • Startup: Read back the intended trigger and image settings before enabling capture.
  • Freshness: Confirm that each accepted request produces the expected new visible scene.
  • Ownership: Delay saving deliberately and check that the owned image remains unchanged after buffer release.
  • Responsiveness: Move the application window during capture and saving; the interface should remain responsive.
  • Failure handling: Test an unavailable destination and interrupted camera connection without reporting false success.
  • Queue limits: Press capture repeatedly and verify the documented busy or rejection behavior.
  • File integrity: Reopen saved files and compare dimensions, representation and selected pixel values.
  • Shutdown: Close the application during a pending request and verify orderly resource cleanup.

Keep diagnostic overlays separate from saved measurement pixels unless the output explicitly requires annotations. The guide to camera preview overlays explains that separation.

Bring your required image format, operating system, capture cadence and freshness criteria to the camera configurator. For help checking the acquisition contract before selecting hardware, use applications support.

Questions

Does reading the next camera frame take a new picture?

Not necessarily. A read call can return an image that was exposed earlier and remained in a queue. A new-exposure promise requires supported triggering, a known acquisition state and a way to associate the completed image with the accepted request. Saving a preview frame is a different operation.

Should the application reopen the camera for every capture?

Keep one session open when the SDK and application lifecycle support it. Configure the device deliberately, start the appropriate triggered acquisition mode, and handle requests through one acquisition owner. Reopening for each click adds connection overhead and makes configuration consistency harder to maintain.

Why does a saved image change or become corrupted after capture?

This commonly happens when the save operation still references transport-owned memory after its buffer has been requeued. Make an independent pixel copy before release. Also verify stride, pixel format and channel interpretation, because an incorrect image layout can produce similar symptoms.

What should happen when a software-triggered capture times out?

Treat a post-trigger timeout as an uncertain result rather than immediately issuing another trigger. An exposure may already have occurred. Record the failed request, follow the SDK's documented stop or recovery sequence, and restore a known queue and trigger state before accepting another request.

Can a smart camera support the same GUI capture workflow?

Only when the selected device and software interface support the required trigger and image-transfer operations. Some workflows return inspection results without transferring full images. Check image retrieval, pixel formats, licensing requirements and host API support separately from the device's inspection capabilities.