@@ -222,12 +222,15 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
double analogueGain = frameContext.sensor.gain;
utils::Duration effectiveExposureValue = exposureTime * analogueGain;
+ /* \todo Plumb in the lux value. Requires a lux algo + tuning */
+ double lux = 400;
+
utils::Duration shutterTime;
double aGain, dGain;
std::tie(shutterTime, aGain, dGain) =
calculateNewEv(context.activeState.agc.constraintMode,
context.activeState.agc.exposureMode, hist,
- effectiveExposureValue);
+ effectiveExposureValue, lux);
LOG(IPU3Agc, Debug)
<< "Divided up shutter, analogue gain and digital gain are "
@@ -134,7 +134,7 @@ static constexpr double kDefaultRelativeLuminanceTarget = 0.16;
*/
AgcMeanLuminance::AgcMeanLuminance()
- : frameCount_(0), filteredExposure_(0s), relativeLuminanceTarget_(0)
+ : frameCount_(0), filteredExposure_(0s)
{
}
@@ -142,8 +142,17 @@ AgcMeanLuminance::~AgcMeanLuminance() = default;
void AgcMeanLuminance::parseRelativeLuminanceTarget(const YamlObject &tuningData)
{
- relativeLuminanceTarget_ =
- tuningData["relativeLuminanceTarget"].get<double>(kDefaultRelativeLuminanceTarget);
+ int ret = relativeLuminanceTarget_.readYaml(tuningData["relativeLuminanceTarget"]);
+ if (ret == 0)
+ return;
+
+ LOG(AgcMeanLuminance, Warning)
+ << "Failed to load tuning parameter 'relativeLuminanceTarget', "
+ << "using default [0, " << kDefaultRelativeLuminanceTarget << "]";
+
+ std::vector<PointF> points = { { 0, kDefaultRelativeLuminanceTarget },
+ { 10000, kDefaultRelativeLuminanceTarget } };
+ relativeLuminanceTarget_ = Pwl(points);
}
void AgcMeanLuminance::parseConstraint(const YamlObject &modeDict, int32_t id)
@@ -421,11 +430,18 @@ void AgcMeanLuminance::setLimits(utils::Duration minShutter,
/**
* \brief Estimate the initial gain needed to achieve a relative luminance
* target
+ * \param[in] lux The lux value at which to sample the luminance target pwl
+ *
+ * To account for non-linearity caused by saturation, the value needs to be
+ * estimated in an iterative process, as multiplying by a gain will not increase
+ * the relative luminance by the same factor if some image regions are saturated
+ *
* \return The calculated initial gain
*/
-double AgcMeanLuminance::estimateInitialGain() const
+double AgcMeanLuminance::estimateInitialGain(double lux) const
{
- double yTarget = relativeLuminanceTarget_;
+ double yTarget =
+ relativeLuminanceTarget_.eval(relativeLuminanceTarget_.domain().clamp(lux));
double yGain = 1.0;
/*
@@ -520,6 +536,7 @@ utils::Duration AgcMeanLuminance::filterExposure(utils::Duration exposureValue)
* the calculated gain
* \param[in] effectiveExposureValue The EV applied to the frame from which the
* statistics in use derive
+ * \param[in] lux The lux value at which to sample the luminance target pwl
*
* 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
@@ -531,7 +548,8 @@ std::tuple<utils::Duration, double, double>
AgcMeanLuminance::calculateNewEv(uint32_t constraintModeIndex,
uint32_t exposureModeIndex,
const Histogram &yHist,
- utils::Duration effectiveExposureValue)
+ utils::Duration effectiveExposureValue,
+ double lux)
{
/*
* The pipeline handler should validate that we have received an allowed
@@ -540,7 +558,7 @@ AgcMeanLuminance::calculateNewEv(uint32_t constraintModeIndex,
std::shared_ptr<ExposureModeHelper> exposureModeHelper =
exposureModeHelpers_.at(exposureModeIndex);
- double gain = estimateInitialGain();
+ double gain = estimateInitialGain(lux);
gain = constraintClampGain(constraintModeIndex, yHist, gain);
/*
@@ -18,6 +18,7 @@
#include "exposure_mode_helper.h"
#include "histogram.h"
+#include "pwl.h"
namespace libcamera {
@@ -62,7 +63,7 @@ public:
std::tuple<utils::Duration, double, double>
calculateNewEv(uint32_t constraintModeIndex, uint32_t exposureModeIndex,
- const Histogram &yHist, utils::Duration effectiveExposureValue);
+ const Histogram &yHist, utils::Duration effectiveExposureValue, double lux);
void resetFrameCount()
{
@@ -76,7 +77,7 @@ private:
void parseConstraint(const YamlObject &modeDict, int32_t id);
int parseConstraintModes(const YamlObject &tuningData);
int parseExposureModes(const YamlObject &tuningData);
- double estimateInitialGain() const;
+ double estimateInitialGain(double lux) const;
double constraintClampGain(uint32_t constraintModeIndex,
const Histogram &hist,
double gain);
@@ -84,7 +85,7 @@ private:
uint64_t frameCount_;
utils::Duration filteredExposure_;
- double relativeLuminanceTarget_;
+ Pwl relativeLuminanceTarget_;
std::map<int32_t, std::vector<AgcConstraint>> constraintModes_;
std::map<int32_t, std::shared_ptr<ExposureModeHelper>> exposureModeHelpers_;
@@ -379,12 +379,15 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
double analogueGain = frameContext.sensor.gain;
utils::Duration effectiveExposureValue = exposureTime * analogueGain;
+ /* \todo Plumb in the lux value. Requires a lux algo + tuning */
+ double lux = 400;
+
utils::Duration shutterTime;
double aGain, dGain;
std::tie(shutterTime, aGain, dGain) =
calculateNewEv(context.activeState.agc.constraintMode,
context.activeState.agc.exposureMode,
- hist, effectiveExposureValue);
+ hist, effectiveExposureValue, lux);
LOG(RkISP1Agc, Debug)
<< "Divided up shutter, analogue gain and digital gain are "