diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp index 39d0aebb..da045640 100644 --- a/src/ipa/ipu3/algorithms/agc.cpp +++ b/src/ipa/ipu3/algorithms/agc.cpp @@ -222,8 +222,8 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, utils::Duration effectiveExposureValue = exposureTime * analogueGain; utils::Duration newExposureTime; - double aGain, dGain; - std::tie(newExposureTime, aGain, dGain) = + double aGain, qGain, dGain; + std::tie(newExposureTime, aGain, qGain, dGain) = calculateNewEv(context.activeState.agc.constraintMode, context.activeState.agc.exposureMode, hist, effectiveExposureValue); diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp index ea4709bf..41c7f72d 100644 --- a/src/ipa/libipa/agc_mean_luminance.cpp +++ b/src/ipa/libipa/agc_mean_luminance.cpp @@ -566,11 +566,12 @@ utils::Duration AgcMeanLuminance::filterExposure(utils::Duration exposureValue) * * Calculate a new exposure value to try to obtain the target. The calculated * exposure value is filtered to prevent rapid changes from frame to frame, and - * divided into exposure time, analogue and digital gain. + * divided into exposure time, analogue, quantization and digital gain. * - * \return Tuple of exposure time, analogue gain, and digital gain + * \return Tuple of exposure time, analogue gain, quantization gain and digital + * gain */ -std::tuple +std::tuple AgcMeanLuminance::calculateNewEv(uint32_t constraintModeIndex, uint32_t exposureModeIndex, const Histogram &yHist, diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h index 49985481..fbb526f6 100644 --- a/src/ipa/libipa/agc_mean_luminance.h +++ b/src/ipa/libipa/agc_mean_luminance.h @@ -68,7 +68,7 @@ public: return controls_; } - std::tuple + std::tuple calculateNewEv(uint32_t constraintModeIndex, uint32_t exposureModeIndex, const Histogram &yHist, utils::Duration effectiveExposureValue); diff --git a/src/ipa/libipa/exposure_mode_helper.cpp b/src/ipa/libipa/exposure_mode_helper.cpp index f2de1d8e..29e316d9 100644 --- a/src/ipa/libipa/exposure_mode_helper.cpp +++ b/src/ipa/libipa/exposure_mode_helper.cpp @@ -178,14 +178,24 @@ double ExposureModeHelper::clampGain(double gain, double *quantizationGain) cons * required exposure, the helper falls-back to simply maximising the exposure * time first, followed by analogue gain, followed by digital gain. * - * \return Tuple of exposure time, analogue gain, and digital gain + * During the calculations the gain missed due to quantization is recorded and + * returned as quantization gain. The quantization gain is not included in the + * digital gain. So to exactly apply the given exposure, both quantization gain + * and digital gain must be applied. + * + * \return Tuple of exposure time, analogue gain, quantization gain and digital + * gain */ -std::tuple +std::tuple ExposureModeHelper::splitExposure(utils::Duration exposure) const { ASSERT(maxExposureTime_); ASSERT(maxGain_); + utils::Duration exposureTime; + double gain; + double quantGain; + double quantGain2; bool gainFixed = minGain_ == maxGain_; bool exposureTimeFixed = minExposureTime_ == maxExposureTime_; @@ -193,16 +203,21 @@ ExposureModeHelper::splitExposure(utils::Duration exposure) const * There's no point entering the loop if we cannot change either gain * nor exposure time anyway. */ - if (exposureTimeFixed && gainFixed) - return { minExposureTime_, minGain_, exposure / (minExposureTime_ * minGain_) }; + if (exposureTimeFixed && gainFixed) { + exposureTime = clampExposureTime(minExposureTime_, &quantGain); + gain = clampGain(minGain_, &quantGain2); + quantGain *= quantGain2; + + return { exposureTime, gain, quantGain, + exposure / (exposureTime * gain * quantGain) }; + } - utils::Duration exposureTime; double stageGain = clampGain(1.0); double lastStageGain = stageGain; - double gain; for (unsigned int stage = 0; stage < gains_.size(); stage++) { - utils::Duration stageExposureTime = clampExposureTime(exposureTimes_[stage]); + utils::Duration stageExposureTime = clampExposureTime(exposureTimes_[stage], + &quantGain); stageGain = clampGain(gains_[stage]); /* @@ -215,18 +230,22 @@ ExposureModeHelper::splitExposure(utils::Duration exposure) const /* Clamp the gain to lastStageGain and regulate exposureTime. */ if (stageExposureTime * lastStageGain >= exposure) { - exposureTime = clampExposureTime(exposure / lastStageGain); - gain = clampGain(exposure / exposureTime); + exposureTime = clampExposureTime(exposure / lastStageGain, &quantGain); + gain = clampGain(exposure / exposureTime, &quantGain2); + quantGain *= quantGain2; - return { exposureTime, gain, exposure / (exposureTime * gain) }; + return { exposureTime, gain, quantGain, + exposure / (exposureTime * gain * quantGain) }; } /* Clamp the exposureTime to stageExposureTime and regulate gain. */ if (stageExposureTime * stageGain >= exposure) { exposureTime = stageExposureTime; - gain = clampGain(exposure / exposureTime); + gain = clampGain(exposure / exposureTime, &quantGain2); + quantGain *= quantGain2; - return { exposureTime, gain, exposure / (exposureTime * gain) }; + return { exposureTime, gain, quantGain, + exposure / (exposureTime * gain * quantGain) }; } lastStageGain = stageGain; @@ -239,10 +258,12 @@ ExposureModeHelper::splitExposure(utils::Duration exposure) const * stages to use then the default stageGain of 1.0 is used so that * exposure time is maxed before gain is touched at all. */ - exposureTime = clampExposureTime(exposure / stageGain); - gain = clampGain(exposure / exposureTime); + exposureTime = clampExposureTime(exposure / stageGain, &quantGain); + gain = clampGain(exposure / exposureTime, &quantGain2); + quantGain *= quantGain2; - return { exposureTime, gain, exposure / (exposureTime * gain) }; + return { exposureTime, gain, quantGain, + exposure / (exposureTime * gain * quantGain) }; } /** diff --git a/src/ipa/libipa/exposure_mode_helper.h b/src/ipa/libipa/exposure_mode_helper.h index ac7e8da9..968192dd 100644 --- a/src/ipa/libipa/exposure_mode_helper.h +++ b/src/ipa/libipa/exposure_mode_helper.h @@ -30,7 +30,7 @@ public: void setLimits(utils::Duration minExposureTime, utils::Duration maxExposureTime, double minGain, double maxGain); - std::tuple + std::tuple splitExposure(utils::Duration exposure) const; utils::Duration minExposureTime() const { return minExposureTime_; } diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp index 15963994..88f8664c 100644 --- a/src/ipa/mali-c55/algorithms/agc.cpp +++ b/src/ipa/mali-c55/algorithms/agc.cpp @@ -381,8 +381,8 @@ void Agc::process(IPAContext &context, utils::Duration effectiveExposureValue = currentShutter * totalGain; utils::Duration shutterTime; - double aGain, dGain; - std::tie(shutterTime, aGain, dGain) = + double aGain, qGain, dGain; + std::tie(shutterTime, aGain, qGain, dGain) = calculateNewEv(activeState.agc.constraintMode, activeState.agc.exposureMode, statistics_.yHist, effectiveExposureValue); diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index 35440b67..0a293268 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -567,15 +567,16 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, setExposureCompensation(pow(2.0, frameContext.agc.exposureValue)); utils::Duration newExposureTime; - double aGain, dGain; - std::tie(newExposureTime, aGain, dGain) = + double aGain, qGain, dGain; + std::tie(newExposureTime, aGain, qGain, dGain) = calculateNewEv(frameContext.agc.constraintMode, frameContext.agc.exposureMode, hist, effectiveExposureValue); LOG(RkISP1Agc, Debug) - << "Divided up exposure time, analogue gain and digital gain are " - << newExposureTime << ", " << aGain << " and " << dGain; + << "Divided up exposure time, analogue gain, quantization gain" + << " and digital gain are " << newExposureTime << ", " << aGain + << ", " << qGain << " and " << dGain; IPAActiveState &activeState = context.activeState; /* Update the estimated exposure and gain. */