[PATCH v2] ipa: libipa: Change constraint Y target to piecewise linear function
Paul Elder
paul.elder at ideasonboard.com
Wed Jun 5 11:59:56 CEST 2024
On Mon, Jun 03, 2024 at 01:24:18PM +0100, Kieran Bingham wrote:
> Quoting Paul Elder (2024-05-29 20:33:22)
> > Change the constraint luminance target from a scalar value to a
> > piecewise linear function that needs to be sampled by the estimated lux
> > value.
> >
> > Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
> >
> > ---
> > Changes in v2:
> > - s/FPoint/PointF/
> > - construct default Pwl with *two* points so that it actually constructs
> > properly
> > ---
> > src/ipa/libipa/agc_mean_luminance.cpp | 15 +++++++++------
> > src/ipa/libipa/agc_mean_luminance.h | 4 ++--
> > 2 files changed, 11 insertions(+), 8 deletions(-)
> >
> > diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp
> > index 5b79d5d59..5eaa86c82 100644
> > --- a/src/ipa/libipa/agc_mean_luminance.cpp
> > +++ b/src/ipa/libipa/agc_mean_luminance.cpp
> > @@ -168,8 +168,10 @@ void AgcMeanLuminance::parseConstraint(const YamlObject &modeDict, int32_t id)
> > AgcConstraint::Bound bound = static_cast<AgcConstraint::Bound>(idx);
> > double qLo = content["qLo"].get<double>().value_or(0.98);
> > double qHi = content["qHi"].get<double>().value_or(1.0);
> > - double yTarget =
> > - content["yTarget"].getList<double>().value_or(std::vector<double>{ 0.5 }).at(0);
> > + Pwl yTarget;
> > + int ret = yTarget.readYaml(content["yTarget"]);
> > + if (ret < 0)
> > + yTarget = Pwl({ PointF(0, 0.5), PointF(1000, 0.5) });
>
> Is the 'length' of the Pwl arbitrary? Does it extend if we go above
> '1000' here? From this snipped/hunk - I don't know what units/reference
> 0 and 1000 are? Is it the lux value?
>
> Can any reasoning for 0...1000 be documented? I assume 0.5 is just 'half
> brightness target' if that's sufficiently self explanatory then fine -
> but even that might warrant a couple of words in why it's chosen?
>
> Googling lux levels tells me:
>
> - Direct Sunlight 32,000 to 100,000
> - Ambient Daylight 10,000 to 25,000
> - Overcast Daylight 1000
> - Sunset & Sunrise 400
>
> Does that impact the choice of '1000' here? As the two points make a
> linear that will always return 0.5 - I assume it doesn't matter here,
> and
>
> Pwl({ PointF(0, 0.5), PointF(1, 0.5) });
>
> would also have been equivalent ?
Yes it would be. Since this is a constant function, the input doesn't
matter and extrapolation and clamping are equivalent.
>
> >
> > AgcConstraint constraint = { bound, qLo, qHi, yTarget };
> >
> > @@ -221,7 +223,7 @@ int AgcMeanLuminance::parseConstraintModes(const YamlObject &tuningData)
> > AgcConstraint::Bound::lower,
> > 0.98,
> > 1.0,
> > - 0.5
> > + Pwl({ PointF(0, 0.5), PointF(1000, 0.5) })
>
> Should this be some pre-constructed global const if it's going to be
> used in multiple places?
Probably? It's used three times; twice here and once more for
relativeLuminance.
Paul
>
>
> > };
> >
> > constraintModes_[controls::ConstraintNormal].insert(
> > @@ -471,16 +473,17 @@ double AgcMeanLuminance::estimateInitialGain(double lux) const
> > * \param[in] constraintModeIndex The index of the constraint to adhere to
> > * \param[in] hist A histogram over which to calculate inter-quantile means
> > * \param[in] gain The gain to clamp
> > + * \param[in] lux The lux value at which to sample the constraint luminance target pwl
> > *
> > * \return The gain clamped within the constraint bounds
> > */
> > double AgcMeanLuminance::constraintClampGain(uint32_t constraintModeIndex,
> > const Histogram &hist,
> > - double gain)
> > + double gain, double lux)
> > {
> > std::vector<AgcConstraint> &constraints = constraintModes_[constraintModeIndex];
> > for (const AgcConstraint &constraint : constraints) {
> > - double newGain = constraint.yTarget * hist.bins() /
> > + double newGain = constraint.yTarget.eval(constraint.yTarget.domain().clamp(lux)) * hist.bins() /
> > hist.interQuantileMean(constraint.qLo, constraint.qHi);
> >
> > if (constraint.bound == AgcConstraint::Bound::lower &&
> > @@ -559,7 +562,7 @@ AgcMeanLuminance::calculateNewEv(uint32_t constraintModeIndex,
> > exposureModeHelpers_.at(exposureModeIndex);
> >
> > double gain = estimateInitialGain(lux);
> > - gain = constraintClampGain(constraintModeIndex, yHist, gain);
> > + gain = constraintClampGain(constraintModeIndex, yHist, gain, lux);
> >
> > /*
> > * We don't check whether we're already close to the target, because
> > diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h
> > index 6ec2a0dc9..d43f673dd 100644
> > --- a/src/ipa/libipa/agc_mean_luminance.h
> > +++ b/src/ipa/libipa/agc_mean_luminance.h
> > @@ -38,7 +38,7 @@ public:
> > Bound bound;
> > double qLo;
> > double qHi;
> > - double yTarget;
> > + Pwl yTarget;
> > };
> >
> > int parseTuningData(const YamlObject &tuningData);
> > @@ -80,7 +80,7 @@ private:
> > double estimateInitialGain(double lux) const;
> > double constraintClampGain(uint32_t constraintModeIndex,
> > const Histogram &hist,
> > - double gain);
> > + double gain, double lux);
> > utils::Duration filterExposure(utils::Duration exposureValue);
> >
> > uint64_t frameCount_;
> > --
> > 2.39.2
> >
More information about the libcamera-devel
mailing list