[PATCH v2] ipa: libipa: Change constraint Y target to piecewise linear function

Paul Elder paul.elder at ideasonboard.com
Wed May 29 21:33:22 CEST 2024


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) });
 
 		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



More information about the libcamera-devel mailing list