52 lines
2.1 KiB
C++
52 lines
2.1 KiB
C++
#pragma once
|
|
|
|
#include "fgc/ImageQuality.h"
|
|
|
|
#include <string>
|
|
|
|
namespace fgc {
|
|
|
|
// The exposure/gain control law: given what an image turned out like, decide
|
|
// whether to keep it and what to change if not. Pure (no camera, no I/O, no
|
|
// clock) so the whole correction strategy is unit-testable.
|
|
|
|
struct CaptureSettings {
|
|
double exposure_us = 0.0;
|
|
double gain_db = 0.0;
|
|
};
|
|
|
|
struct PolicyParams {
|
|
double target_mean = 110.0; // desired mean luma, 0..255
|
|
double mean_tolerance = 12.0; // accept within +-this of the target
|
|
double clip_max_fraction = 0.005; // 0.5% blown pixels is the ceiling
|
|
double exposure_min_us = 50.0;
|
|
double exposure_max_us = 20000.0; // doubles as the motion-blur budget
|
|
double gain_max_db = 12.0;
|
|
double damping = 0.8; // <1 damps the correction, preventing oscillation
|
|
// Blur is judged RELATIVE to the same angle's own history: a foggy horizon is
|
|
// legitimately low-detail, so an absolute threshold would retry forever on it.
|
|
double blur_relative_floor = 0.5; // retry below this fraction of the reference
|
|
double blur_absolute_floor = 0.0; // 0 disables the catastrophic-blur backstop
|
|
};
|
|
|
|
struct Verdict {
|
|
bool accept = false;
|
|
std::string reason; // "ok" / "clipped" / "dark" / "bright" / "blur" / "saturated"
|
|
CaptureSettings next; // settings to use for the next attempt (== current if accepting)
|
|
};
|
|
|
|
// Judge one attempt. `reference_sharpness` is this angle's recent sharpness; pass
|
|
// 0 when unknown, which skips the relative blur check.
|
|
//
|
|
// Precedence matters: clipping outranks the mean, because a bright sky can blow
|
|
// out while the average still looks perfectly reasonable - and blown highlights
|
|
// are unrecoverable, whereas a slightly dark frame is not.
|
|
Verdict evaluate(const ImageMetrics& m, const CaptureSettings& current, const PolicyParams& p,
|
|
double reference_sharpness = 0.0);
|
|
|
|
// Rank attempts so "best so far" is well defined: sharpness discounted by how far
|
|
// the exposure strayed. Higher is better.
|
|
double score(const ImageMetrics& m, const PolicyParams& p);
|
|
|
|
} // namespace fgc
|