System designHow-to

Save annotated inspection images in a processing loop

Save annotated inspection images with measurement overlays, unique filenames, fixed export dimensions, and checks for missing or overwritten files.

LumaSpec Vision10 min read Share on LinkedIn

On this page 10 sections
  1. 01Choose what the saved file must contain
  2. 02Prepare the acquisition and export contract
  3. 03Create unique filenames before rendering
  4. 04Render into a fixed image canvas
  5. 05Write the rendered image inside the loop
  6. 06Verify completeness by identity, not count alone
  7. 07Budget storage and export time
  8. 08Diagnose common export failures
  9. 09Final acceptance checklist and next step
  10. 10Questions

A displayed measurement line is not necessarily part of the image buffer you save. Your inspection window can look correct while the exported file contains only the original pixels. For engineers recording inspection sequences, the reliable approach is to render the image and its annotations together, then save that rendered output under a unique filename. Keep unmodified originals separately so you can repeat measurements without painted lines obscuring the evidence.

Choose what the saved file must contain

Decide which output you need before adding a file-writing command to the processing loop. Different export methods save different content.

Output What it contains Appropriate use
Original image Acquired pixels without measurement graphics Reprocessing, calibration checks, algorithm development
Annotated raster Image pixels combined with lines, labels, and markers Inspection review and visual records
Figure or window export Rendered image plus potentially axes, margins, and interface elements Reports where the complete layout matters

For a sequence of inspection records, an annotated raster usually gives the most predictable dimensions. A figure export can also work, provided you control its canvas, margins, and rendering settings.

Saving the original buffer does not automatically include a separate graphics overlay. Conversely, capturing a displayed preview can lose intensity precision or introduce resizing. The guide to saving camera frames for offline testing covers the original-image workflow; use that alongside this annotation-export process.

Prepare the acquisition and export contract

You do not need a different camera merely to save overlays. The export behavior belongs to the application and rendering pipeline, not the camera interface.

If you are selecting acquisition hardware, compare area scan cameras through the camera finder. The LS-CMR-0053 uses GigE. The LS-CMR-0166 uses USB3. Neither interface choice establishes whether your application exports annotation layers.

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
Interface
GigE
Resolution
12 MP
$560.00View partBuild a system with it
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

Applications running on vision controllers need the same checks: supported acquisition software, a renderer, writable storage, and explicit handling of export failures. Confirm software compatibility independently of the available camera connections.

Before implementation, define these output requirements:

  • Original image format and preservation of its intensity values.
  • Annotated image dimensions and color representation.
  • Filename pattern, sequence numbering, and run-directory policy.
  • Measurement coordinates, units, labels, and line thickness.
  • Behavior when rendering or writing fails.

If your originals contain more intensity precision than the review image, follow the separate guidance on saving high-bit-depth camera images. A color review export should not silently become your only retained measurement source.

Create unique filenames before rendering

  1. Create a new output directory for each run. Place originals, annotated images, and the sequence manifest in separate locations under that directory. Refuse to reuse an existing run directory unless you have explicitly selected a documented resume process.

  2. Assign a sequence number to every accepted input. Build the filename from that number, not from a constant string or a timestamp alone. Associate it with the acquisition identifier before processing begins.

For a batch containing 251 inputs, a six-digit pattern produces names from annotated_000001.png through annotated_000251.png. Zero padding makes alphabetical sorting match sequence order. Choose the padding width for the largest expected run, not just the current batch.

A useful directory structure is:

run_20261030_001/
    originals/
        original_000001.tif
    annotated/
        annotated_000001.png
    manifest.csv

These extensions are examples, not interchangeable format guarantees. Confirm that the chosen original-image writer preserves your pixel type and metadata requirements.

Use the runtime's path-joining function rather than manually inserting separators. Check directory creation and write permissions before starting acquisition. A successful directory check does not remove the need to handle later storage errors.

Render into a fixed image canvas

  1. Render the source image and measurements together. Use an image-space drawing operation or a documented export method that includes overlay objects. Set the canvas dimensions explicitly rather than inheriting the current desktop window size.

For a hypothetical source image measuring 1280 × 960 pixels, exporting at the same dimensions avoids unnecessary coordinate scaling. The saved review image then uses the same spatial grid, although its color representation may differ from the original.

If you deliberately resize, transform the annotation coordinates with the image. For uniform scaling with no crop, padding, or rotation:

x_output = scale × x_source y_output = scale × y_source output width = scale × source width output height = scale × source height

A scale of 0.5 maps a source location of (600, 400) to (300, 200). Cropping or letterboxing requires an additional coordinate offset. Coordinate conventions also matter: verify whether the drawing library treats integer coordinates as pixel centers or pixel boundaries.

  1. Reset the rendering state for every frame. Clear previous annotations, draw the current image, then draw only its associated measurements. Reusing a canvas without clearing it can accumulate lines from earlier inspections.

Specify line thickness, colors, label positions, and text size consistently. Do not rely on color alone to distinguish measurements; add labels or different marker styles. Check whether figure-export line thickness is expressed in pixels or physical units, since export resolution can change its appearance.

Write the rendered image inside the loop

  1. Write each completed rendering and check the outcome. The following is pseudocode: its operations describe required behavior, not functions supplied by a particular library.
create_new_run_directory_or_fail()
open_manifest_or_fail()

for sequence_number, input_record in accepted_inputs:
    frame = obtain_owned_frame(input_record)
    measurements = inspect(frame)

    original_path = make_original_path(sequence_number)
    annotated_path = make_annotated_path(sequence_number)
    require_destination_absent(original_path)
    require_destination_absent(annotated_path)

    save_original_checked(frame, original_path)

    canvas = create_fixed_size_canvas()
    draw_source_image(canvas, frame)
    draw_measurements(canvas, measurements)

    temporary_path = make_unique_temporary_path(annotated_path)
    write_png_and_close_checked(canvas, temporary_path)
    decode_and_check_dimensions(temporary_path)
    commit_without_replacing_existing(temporary_path, annotated_path)

    append_manifest_record_checked(
        sequence_number,
        input_record.identifier,
        original_path,
        annotated_path,
        measurements
    )

finalize_manifest_checked()

Implement the commit operation using your runtime's documented filesystem behavior. An ordinary rename may replace an existing destination on some systems. A preliminary existence check alone does not prevent another writer from creating the same filename between checking and committing.

Writing to a temporary file keeps incomplete output out of the final filename namespace. It does not, by itself, guarantee survival through a power interruption. Applications requiring that guarantee need a separately designed durability and recovery procedure.

The frame must remain valid until inspection and rendering finish. If acquisition buffers are recycled, retain ownership according to the acquisition API or make an independent copy before handing data to another worker. The guidance on camera image-buffer ownership explains why retaining a reference may not retain valid pixels.

A failed export should create an explicit failure record or stop the batch according to your policy. Never advance the manifest as though an image was successfully saved when its write failed.

Verify completeness by identity, not count alone

  1. Compare the expected sequence with the saved sequence. Counting files is necessary, but it cannot detect every mismatch. A directory can contain the expected quantity while holding an unrelated extra file and missing a required one.

For the example batch, construct the expected set of 251 annotated filenames. Compare that set with the actual files and report missing names and unexpected names separately. Preserve the relationship between sequence number and acquisition identifier; acquisition identifiers need not be consecutive.

Reopen every exported image during qualification and confirm:

  • The file decodes successfully, rather than merely having a nonzero size.
  • Width, height, and channel representation match the output contract.
  • The measurement line appears on the intended feature.
  • Previous-frame annotations are absent.
  • The manifest links the correct original, overlay image, and measurements.

Use known test coordinates near the center and edges to expose coordinate offsets or clipping. Include a frame with no detected measurement and one with multiple measurements. These cases reveal whether the renderer accidentally carries previous annotations forward.

If decoded pixels differ from your assumptions, review image bytes versus pixel data. Encoded file bytes and decoded pixel arrays require different checks.

Budget storage and export time

A compressed file's size depends on image content and encoder settings. Start with the uncompressed pixel payload as a planning reference, not a prediction of PNG file size.

pixel payload = width × height × channels × bytes per channel required average writer rate = accepted frames per second

For the hypothetical 1280 × 960 output with three channels and one byte per channel:

1280 × 960 × 3 × 1 = 3,686,400 bytes per image

Across the example batch:

3,686,400 × 251 = 925,286,400 bytes, or approximately 925 MB using decimal units.

That calculation excludes originals, manifests, filesystem overhead, and temporary copies. Measure actual compressed sizes using representative images, including textured and noisy scenes.

Timing matters just as much. At an accepted rate of 20 frames per second, a new image arrives every 1000 / 20 = 50 ms. If annotation and writing take 80 ms per frame in a single serial worker, its sustained capacity is only 1000 / 80 = 12.5 frames per second.

A queue can absorb a short burst, but it cannot correct that sustained mismatch. Its backlog grows by approximately 20 − 12.5 = 7.5 frames per second while those rates persist. Use a bounded queue and an explicit overflow policy. Do not silently drop required inspection records.

For offline processing, a synchronous loop is often simpler because it naturally waits for each write. For continuous acquisition, measure capture, inspection, rendering, encoding, and storage time separately before introducing asynchronous workers.

Diagnose common export failures

Symptom Likely cause Practical check and correction
Saved image has no lines Writer received the original buffer Export the composed raster or the documented overlay-aware rendering
Only the last image remains Filename is constant inside the loop Log every destination and include the sequence number
Image dimensions change Export follows window or figure size Fix the canvas and verify dimensions after decoding
Lines accumulate Previous graphics remain on a reused canvas Clear annotations before drawing each frame
Lines are displaced Image and coordinates use different transforms Apply matching resize, crop, and padding transforms
Some files are absent Write failures or queue overflow went unreported Record write outcomes and reconcile expected identities
Correct filename, wrong content Frame buffer changed before rendering Retain valid ownership or copy before asynchronous use

A figure export is the better choice when the required record includes axes, legends, or a complete report layout. An image-space raster is usually easier when exact pixel dimensions matter. Neither choice replaces numerical measurement storage: record coordinates and units separately if later analysis needs them.

Final acceptance checklist and next step

  1. Qualify a short batch before enabling full-run recording. Start with 10 deliberately varied images, then repeat the test with the complete expected batch and realistic storage load.
  • Confirm original pixels remain available without painted annotations.
  • Confirm every accepted input has one expected annotated filename.
  • Confirm duplicate destinations fail rather than overwrite silently.
  • Decode saved files and check dimensions and measurement placement.
  • Simulate a write failure and verify that the application reports it.
  • Rerun the sequence and confirm a new run directory is required.
  • Verify manifest handling after an interrupted run.
  • Measure sustained throughput with the intended annotation density.

For a new acquisition station, begin with the camera configuration step. For an existing station, use applications support to discuss the acquisition interface, original pixel format, required overlay layout, and accepted recording rate before changing hardware.

Questions

Why are measurement lines missing from the saved image?

Usually not when the lines exist in a separate display or graphics layer. Save a composed image or use a documented export method that includes those graphics. Test the saved file independently of the live window, because a correct preview does not prove the annotations were exported.

How do I prevent annotated images from being overwritten?

Use a new run directory, sequence-based filenames, and a write or commit operation that refuses existing destinations. Zero padding improves sorting but does not prevent overwriting. For concurrent writers, use documented exclusive-creation or no-replacement behavior rather than relying only on an earlier existence check.

Which file format should I use for annotated inspection images?

PNG is often suitable for lossless annotated review images. Preserve the original separately in a format that supports its actual pixel type and required metadata. Avoid treating a resized or converted color review image as an equivalent replacement for a higher-precision measurement source.

How can I check that the entire image sequence was saved?

Compare expected sequence identities against saved filenames, then decode the files and validate their dimensions. Reconcile those records with a manifest linking each acquisition identifier to its original image and annotated output. File count alone can conceal a missing image alongside an unexpected extra file.

Can annotated image saving run asynchronously?

Yes, provided frame ownership, queue capacity, and write completion are handled explicitly. The source pixels and associated measurements must remain valid until rendering finishes. Measure sustained writer throughput, bound the queue, and define what happens when storage cannot keep pace with accepted frames.