Skip to content

Lux metadata always 400 with --immediate and manual AWB gains (single-frame capture) #345

@ByteHD

Description

@ByteHD

Hi, I found a problem where the Lux metadata is always stuck at 400.0 when using --immediate with --awbgains set to non-zero values. I've been running with rpicam-still --immediate --awbgains 0,0 --shutter ... --gain ... and Lux was always correct. When I switched to --awbgains 1.3,1.6, Lux became permanently stuck at 400.0.

Setup:

  • Pi 5, HQ camera (IMX477 NoIR)
  • rpicam-still --immediate --nopreview --raw --shutter 2155 --gain 1 --awbgains 1.3,1.6 --denoise off --sharpness 0
  • libcamera 0.7.1+rpt20260429-1
  • Running LIBCAMERA_LOG_LEVELS=RPiLux:DEBUG produces zero RPiLux output, confirming Lux::process() never executes

I don't know cpp well so I asked Claude to check source code and it found what appears to be the following problem. I'd appreciate confirmation if this analysis is correct.

Root cause:

When --awbgains is set to non-zero values, Awb::setManualGains() disables auto AWB. This causes Awb::getConvergenceFrames() to return 0 (awb.cpp:192-201). Combined with manual exposure and gain, AgcChannel::getConvergenceFrames() also returns 0.

In ipa_base.cpp, startupFrameCount is calculated as:

result->startupFrameCount = std::max({ agcConvergenceFrames, awbConvergenceFrames });

With both at 0, startupFrameCount = 0. This means no frames are tagged as FrameStartup in the pipeline, and the very first frame is returned as FrameSuccess.

rpicam-apps drops FrameStartup frames (rpicam_app.cpp:1134-1136), so with --immediate this first FrameSuccess frame is captured immediately.

However, mistrustCount_ is still 1 (from CamHelper::mistrustFramesStartup()). In ipa_base.cpp:527:

if (processPending_ && frameCount_ >= mistrustCount_)

On frame 0, 0 >= 1 is false, so controller_.process() is skipped entirely. Lux::process() never runs. The reported Lux value is the constructor default of 400 (lux.cpp:29).

Why --awbgains 0,0 worked: Awb::setManualGains() checks for zero values and switches back to auto mode (awb.cpp:209). Auto AWB returns convergenceFrames = 3, so startupFrameCount becomes 4 (3 + mistrustCount). Those 4 frames get dropped as FrameStartup, and by the time the first FrameSuccess arrives, frameCount_ is well past mistrustCount_ and Lux::process() has run multiple times.

Impact: This affects any single-frame --immediate capture with fully manual controls (shutter + gain + awbgains). This is common in astrophotography and scientific imaging where exposures can be minutes long, making it impractical to throw away extra frames just to let lux process.

Possible fix: Lux is a passive read-only estimate that doesn't feed back into any control loop. There's no reason to gate it behind the mistrustCount_ guard — the ISP Y statistics are valid from frame 0. Exempting Lux::process() from the mistrust check would fix this without affecting any other algorithm.

Thanks for looking into it and for your help!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions