Message ID | 20240529193322.835594-1-paul.elder@ideasonboard.com |
---|---|
State | Superseded |
Headers | show |
Series |
|
Related | show |
On Thu, May 30, 2024 at 04:33:22AM +0900, Paul Elder wrote: > 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@ideasonboard.com> > > --- I forgot to mention that this patch also depends on v3 of the series "ipa: Move Pwl from Raspberry Pi" Paul > 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) }); > > 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) }) > }; > > 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 >
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@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 ? > > 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? > }; > > 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 >
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@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 > >
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) }); 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) }) }; 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_;
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@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(-)