@@ -25,10 +25,11 @@ namespace ipa::soft::algorithms {
static constexpr unsigned int kExposureBinsCount = 5;
/*
- * The exposure is optimal when the mean sample value of the histogram is
- * in the middle of the range.
+ * The exposure is optimal when the mean sample value of the histogram matches
+ * the configured target. 0.5 (the middle of the range) is a bright default;
+ * sensors tuned for photographic output usually target a lower code value.
*/
-static constexpr float kExposureOptimal = kExposureBinsCount / 2.0;
+static constexpr double kDefaultExposureTarget = 0.5;
/*
* This implements the hysteresis for the exposure adjustment.
@@ -38,9 +39,21 @@ static constexpr float kExposureOptimal = kExposureBinsCount / 2.0;
static constexpr float kExposureSatisfactory = 0.2;
Agc::Agc()
+ : exposureTarget_(kDefaultExposureTarget)
{
}
+int Agc::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData)
+{
+ const ValueNode &target = tuningData["exposureTarget"];
+
+ exposureTarget_ = target.get<double>(kDefaultExposureTarget);
+ LOG(IPASoftExposure, Debug)
+ << "Exposure target " << exposureTarget_;
+
+ return 0;
+}
+
void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV)
{
/*
@@ -53,8 +66,9 @@ void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, dou
int32_t &exposure = frameContext.sensor.exposure;
double &again = frameContext.sensor.gain;
+ const double optimal = exposureTarget_ * kExposureBinsCount;
- if (exposureMSV < kExposureOptimal - kExposureSatisfactory) {
+ if (exposureMSV < optimal - kExposureSatisfactory) {
if (exposure < context.configuration.agc.exposureMax) {
int32_t next = exposure * kExpNumeratorUp / kExpDenominator;
if (next - exposure < 1)
@@ -70,7 +84,7 @@ void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, dou
}
}
- if (exposureMSV > kExposureOptimal + kExposureSatisfactory) {
+ if (exposureMSV > optimal + kExposureSatisfactory) {
if (again > context.configuration.agc.again10) {
double next = again * kExpNumeratorDown / kExpDenominator;
if (again - next < context.configuration.agc.againMinStep)
@@ -19,6 +19,8 @@ public:
Agc();
~Agc() = default;
+ int init(IPAContext &context, const ValueNode &tuningData) override;
+
void process(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
const SwIspStats *stats,
@@ -26,6 +28,8 @@ public:
private:
void updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV);
+
+ double exposureTarget_;
};
} /* namespace ipa::soft::algorithms */
The simple IPA AGC targets the middle of the histogram range, i.e. a mean sample value of 0.5. As the debayer step gamma-encodes its output (the default gamma is 2.2), such a target maps to roughly 73% of the full code range on output, which looks washed out and clips highlights in scenes with a high dynamic range. Allow platforms to override the target from the tuning file with a new "exposureTarget" parameter, expressed as a fraction of the histogram range. The default keeps the existing behaviour, so existing tuning files keep their meaning. Signed-off-by: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn> --- src/ipa/simple/algorithms/agc.cpp | 24 +++++++++++++++++++----- src/ipa/simple/algorithms/agc.h | 4 ++++ 2 files changed, 23 insertions(+), 5 deletions(-)