ipa: libipa: agc_mean_luminance: Change luminance target to piecewise linear function
In some situations it is necessary to specify the target brightness value depending on the overall lux level. Replace the float relativeLuminanceTraget by a PWL. As the PWL loading code loads a plain value as single point PWL, backwards compatibility to existing tuning files is ensured. While at it, order the class members in reverse xmas tree notation. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com> Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
@@ -54,6 +54,14 @@ static constexpr double kDefaultRelativeLuminanceTarget = 0.16;
|
||||
*/
|
||||
static constexpr double kMaxRelativeLuminanceTarget = 0.95;
|
||||
|
||||
/*
|
||||
* Default lux level
|
||||
*
|
||||
* If no lux level or a zero lux level is specified, but PWLs are used to
|
||||
* specify luminance targets, this default level is used.
|
||||
*/
|
||||
static constexpr unsigned int kDefaultLuxLevel = 500;
|
||||
|
||||
/**
|
||||
* \struct AgcMeanLuminance::AgcConstraint
|
||||
* \brief The boundaries and target for an AeConstraintMode constraint
|
||||
@@ -144,17 +152,30 @@ static constexpr double kMaxRelativeLuminanceTarget = 0.95;
|
||||
*/
|
||||
|
||||
AgcMeanLuminance::AgcMeanLuminance()
|
||||
: exposureCompensation_(1.0), frameCount_(0), filteredExposure_(0s),
|
||||
relativeLuminanceTarget_(0)
|
||||
: filteredExposure_(0s), luxWarningEnabled_(true),
|
||||
exposureCompensation_(1.0), frameCount_(0), lux_(0)
|
||||
{
|
||||
}
|
||||
|
||||
AgcMeanLuminance::~AgcMeanLuminance() = default;
|
||||
|
||||
void AgcMeanLuminance::parseRelativeLuminanceTarget(const YamlObject &tuningData)
|
||||
int AgcMeanLuminance::parseRelativeLuminanceTarget(const YamlObject &tuningData)
|
||||
{
|
||||
relativeLuminanceTarget_ =
|
||||
tuningData["relativeLuminanceTarget"].get<double>(kDefaultRelativeLuminanceTarget);
|
||||
auto &target = tuningData["relativeLuminanceTarget"];
|
||||
if (!target) {
|
||||
relativeLuminanceTarget_ = { { { { 0.0, kDefaultRelativeLuminanceTarget } } } };
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto pwl = target.get<Pwl>();
|
||||
if (!pwl) {
|
||||
LOG(AgcMeanLuminance, Error)
|
||||
<< "Failed to load relative luminance target.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
relativeLuminanceTarget_ = std::move(*pwl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AgcMeanLuminance::parseConstraint(const YamlObject &modeDict, int32_t id)
|
||||
@@ -325,6 +346,8 @@ void AgcMeanLuminance::configure(utils::Duration lineDuration,
|
||||
{
|
||||
for (auto &[id, helper] : exposureModeHelpers_)
|
||||
helper->configure(lineDuration, sensorHelper);
|
||||
|
||||
luxWarningEnabled_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,7 +408,9 @@ int AgcMeanLuminance::parseTuningData(const YamlObject &tuningData)
|
||||
{
|
||||
int ret;
|
||||
|
||||
parseRelativeLuminanceTarget(tuningData);
|
||||
ret = parseRelativeLuminanceTarget(tuningData);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = parseConstraintModes(tuningData);
|
||||
if (ret)
|
||||
@@ -403,6 +428,16 @@ int AgcMeanLuminance::parseTuningData(const YamlObject &tuningData)
|
||||
* AGC calculations. It is expressed as gain instead of EV.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn AgcMeanLuminance::setLux(int lux)
|
||||
* \brief Set the lux level
|
||||
* \param[in] lux The lux level
|
||||
*
|
||||
* This function sets the lux level to be used in the AGC calculations. A value
|
||||
* of 0 means no measurement and a default value of \a kDefaultLuxLevel is used
|
||||
* if necessary.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Set the ExposureModeHelper limits for this class
|
||||
* \param[in] minExposureTime Minimum exposure time to allow
|
||||
@@ -538,7 +573,32 @@ double AgcMeanLuminance::constraintClampGain(uint32_t constraintModeIndex,
|
||||
*/
|
||||
double AgcMeanLuminance::effectiveYTarget() const
|
||||
{
|
||||
return std::min(relativeLuminanceTarget_ * exposureCompensation_,
|
||||
double lux = lux_;
|
||||
if (relativeLuminanceTarget_.size() > 1 && lux_ == 0) {
|
||||
/*
|
||||
* Warn after a few frames if there is still no lux measurement
|
||||
* available. The number of 10 is chosen a bit arbitrarily. It
|
||||
* is big enough to skip the frames that get queued on start
|
||||
* (and therefore are expected to have no valid lux value) and
|
||||
* small enough to show up quickly.
|
||||
*/
|
||||
if (frameCount_ > 10 && luxWarningEnabled_) {
|
||||
luxWarningEnabled_ = false;
|
||||
LOG(AgcMeanLuminance, Warning)
|
||||
<< "Missing lux value for luminance target "
|
||||
"calculation, default to "
|
||||
<< kDefaultLuxLevel
|
||||
<< ". Note that the Lux algorithm must be "
|
||||
"included before the Agc algorithm.";
|
||||
}
|
||||
|
||||
lux = kDefaultLuxLevel;
|
||||
}
|
||||
|
||||
double luminanceTarget = relativeLuminanceTarget_.eval(
|
||||
relativeLuminanceTarget_.domain().clamp(lux));
|
||||
|
||||
return std::min(luminanceTarget * exposureCompensation_,
|
||||
kMaxRelativeLuminanceTarget);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "exposure_mode_helper.h"
|
||||
#include "histogram.h"
|
||||
#include "pwl.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
@@ -50,6 +51,11 @@ public:
|
||||
exposureCompensation_ = gain;
|
||||
}
|
||||
|
||||
void setLux(unsigned int lux)
|
||||
{
|
||||
lux_ = lux;
|
||||
}
|
||||
|
||||
void setLimits(utils::Duration minExposureTime, utils::Duration maxExposureTime,
|
||||
double minGain, double maxGain, std::vector<AgcConstraint> constraints);
|
||||
|
||||
@@ -82,7 +88,7 @@ public:
|
||||
private:
|
||||
virtual double estimateLuminance(const double gain) const = 0;
|
||||
|
||||
void parseRelativeLuminanceTarget(const YamlObject &tuningData);
|
||||
int parseRelativeLuminanceTarget(const YamlObject &tuningData);
|
||||
void parseConstraint(const YamlObject &modeDict, int32_t id);
|
||||
int parseConstraintModes(const YamlObject &tuningData);
|
||||
int parseExposureModes(const YamlObject &tuningData);
|
||||
@@ -92,10 +98,12 @@ private:
|
||||
double gain);
|
||||
utils::Duration filterExposure(utils::Duration exposureValue);
|
||||
|
||||
double exposureCompensation_;
|
||||
uint64_t frameCount_;
|
||||
utils::Duration filteredExposure_;
|
||||
double relativeLuminanceTarget_;
|
||||
mutable bool luxWarningEnabled_;
|
||||
double exposureCompensation_;
|
||||
Pwl relativeLuminanceTarget_;
|
||||
uint64_t frameCount_;
|
||||
unsigned int lux_;
|
||||
|
||||
std::vector<AgcConstraint> additionalConstraints_;
|
||||
std::map<int32_t, std::vector<AgcConstraint>> constraintModes_;
|
||||
|
||||
@@ -618,6 +618,7 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
|
||||
effectiveExposureValue *= frameContext.agc.quantizationGain;
|
||||
|
||||
setExposureCompensation(pow(2.0, frameContext.agc.exposureValue));
|
||||
setLux(frameContext.lux.lux);
|
||||
|
||||
utils::Duration newExposureTime;
|
||||
double aGain, qGain, dGain;
|
||||
|
||||
Reference in New Issue
Block a user