@@ -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);
@@ -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<utils::Duration, double, double>
+std::tuple<utils::Duration, double, double, double>
AgcMeanLuminance::calculateNewEv(uint32_t constraintModeIndex,
uint32_t exposureModeIndex,
const Histogram &yHist,
@@ -68,7 +68,7 @@ public:
return controls_;
}
- std::tuple<utils::Duration, double, double>
+ std::tuple<utils::Duration, double, double, double>
calculateNewEv(uint32_t constraintModeIndex, uint32_t exposureModeIndex,
const Histogram &yHist, utils::Duration effectiveExposureValue);
@@ -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<utils::Duration, double, double>
+std::tuple<utils::Duration, double, double, double>
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) };
}
/**
@@ -30,7 +30,7 @@ public:
void setLimits(utils::Duration minExposureTime, utils::Duration maxExposureTime,
double minGain, double maxGain);
- std::tuple<utils::Duration, double, double>
+ std::tuple<utils::Duration, double, double, double>
splitExposure(utils::Duration exposure) const;
utils::Duration minExposureTime() const { return minExposureTime_; }
@@ -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);
@@ -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. */