[3/5] ipa: libipa: awb: Report AwbState
diff mbox series

Message ID 20260928-awb-state-v1-3-9b1bb8b9e51b@ideasonboard.com
State New
Headers show
Series
  • Add AwbState metadata and AwbTrigger control
Related show

Commit Message

Dan Scally Sept. 28, 2026, 11:13 a.m. UTC
Report the AwbState in metadata. At the moment the implementation
only covers the AwbStateSearching and AwbStateConverged enum values.
Where the calculated gains for a frame have been within 10% of those
calculated for the previous frame for 5 frames, the algorithm is
treated as having converged and the gains calculated for this frame
are recorded, and AwbState reports AwbStateConverged. If the gains
calculated for any subsequent frame stray more than 10% from those
recorded gains the state returns to AwbStateSearching.

Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
---
 src/ipa/libipa/awb.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/ipa/libipa/awb.h   |  5 ++++
 2 files changed, 65 insertions(+), 2 deletions(-)

Patch
diff mbox series

diff --git a/src/ipa/libipa/awb.cpp b/src/ipa/libipa/awb.cpp
index 0e312690b8d2becccbb1405d93cac9c04b2d61a4..d1a75020843a03b3530dce4b6bd82f228ec6bed9 100644
--- a/src/ipa/libipa/awb.cpp
+++ b/src/ipa/libipa/awb.cpp
@@ -17,6 +17,8 @@ 
 constexpr int32_t kMinColourTemperature = 2500;
 constexpr int32_t kMaxColourTemperature = 10000;
 constexpr int32_t kDefaultColourTemperature = 5000;
+constexpr double kConvergenceErrorMargin = 0.10;
+constexpr unsigned int kNumFramesForConvergence = 5;
 
 /**
  * \file awb.h
@@ -255,6 +257,8 @@  int AwbAlgorithmBase::configure(awb::ActiveState &state)
 	state.manual.colourTemperature = kDefaultColourTemperature;
 	state.automatic.colourTemperature = kDefaultColourTemperature;
 
+	lockedCount_ = 0;
+
 	return 0;
 }
 
@@ -351,6 +355,57 @@  void AwbAlgorithmBase::prepare(awb::ActiveState &state,
 	}
 }
 
+/*
+ * We want to assess whether the algorithm has "converged" or not. When we're in
+ * the Searching state then we look for stability of the calculated gains within
+ * 10% of the previous frame's calculated gain, for at least 5 frames. Greater
+ * than 10% but within 15% difference does not count towards those 5 frames, but
+ * will not reset the count. More than 15% difference from the last frame resets
+ * it.
+ *
+ * Once we have reached convergence the gains that were calculated for that
+ * frame are recorded, and future frames gains are compared against those gains
+ * instead of the previous frame's gains. A difference greater than 10% will
+ * cause the state to return to Searching.
+ */
+void AwbAlgorithmBase::updateConvergedState(RGB<double> &oldGains, RGB<double> &newGains)
+{
+	if (convergedState_ == controls::AwbStateEnum::AwbStateSearching) {
+		RGB<double> smallGainError = oldGains * kConvergenceErrorMargin;
+		RGB<double> bigGainError = smallGainError * 1.5;
+
+		if (newGains <= oldGains - bigGainError ||
+		    newGains >= oldGains + bigGainError) {
+			lockedCount_ = 0;
+		} else if (newGains <= oldGains - smallGainError ||
+			   newGains >= oldGains + smallGainError) {
+			// do nothing in this case
+		} else {
+			lockedCount_ = std::min(lockedCount_ + 1, kNumFramesForConvergence);
+		}
+
+		if (lockedCount_ == kNumFramesForConvergence) {
+			convergedGains_ = newGains;
+			convergedState_ = controls::AwbStateEnum::AwbStateConverged;
+		}
+
+		return;
+	}
+
+	/*
+	 * If we're not AwbStateSearching then we're converged, and we check to
+	 * make sure that we have not strayed too far from the converged gains.
+	 */
+
+	RGB<double> gainError = convergedGains_ * kConvergenceErrorMargin;
+
+	if (newGains < convergedGains_ - gainError ||
+	    newGains > convergedGains_ + gainError) {
+		convergedState_ = controls::AwbStateEnum::AwbStateSearching;
+		lockedCount_ = 0;
+	}
+}
+
 /**
  * \brief Process AWB statistics to calculate gains and populate metadata
  * \param[in] state The AWB active state
@@ -384,15 +439,18 @@  void AwbAlgorithmBase::process(awb::ActiveState &state,
 	double ct = awbResult.colourTemperature;
 	ct = ct * speed + state.automatic.colourTemperature * (1 - speed);
 
+	RGB<double> newGains = awbResult.gains * speed +
+			       state.automatic.gains * (1 - speed);
+	updateConvergedState(state.automatic.gains, newGains);
 	state.automatic.colourTemperature = awbResult.colourTemperature;
-	state.automatic.gains = awbResult.gains * speed +
-				state.automatic.gains * (1 - speed);
+	state.automatic.gains = newGains;
 
 	/* Populate metadata. */
 	metadata.set(controls::AwbEnable, frameContext.autoEnabled);
 	metadata.set(controls::ColourGains, { static_cast<float>(frameContext.gains.r()),
 					      static_cast<float>(frameContext.gains.b()) });
 	metadata.set(controls::ColourTemperature, frameContext.colourTemperature);
+	metadata.set(controls::AwbState, convergedState_);
 
 	LOG(Awb, Debug) << std::showpoint << "Means " << stats.rgbMeans()
 			<< ", gains " << state.automatic.gains
diff --git a/src/ipa/libipa/awb.h b/src/ipa/libipa/awb.h
index ef9e78b1e819331b71c06cb48f91bfad0857d10c..5d80f241ec92280e867af5f9724471c5784683d1 100644
--- a/src/ipa/libipa/awb.h
+++ b/src/ipa/libipa/awb.h
@@ -102,11 +102,16 @@  private:
 
 	int parseModeConfigs(const ValueNode &tuningData,
 			     const ControlValue &def = {});
+	void updateConvergedState(RGB<double> &oldGains, RGB<double> &newGains);
 
 	std::map<controls::AwbModeEnum, AwbAlgorithmBase::ModeConfig> modes_;
 	const ModeConfig *currentMode_ = nullptr;
 	std::unique_ptr<AwbImplementation> impl_;
 	bool bayes_ = false;
+
+	controls::AwbStateEnum convergedState_;
+	RGB<double> convergedGains_;
+	unsigned int lockedCount_;
 };
 
 template<typename Q>