[PATCH v1 4/8] ipa: rkisp1: Use interpolator in lsc

Stefan Klug stefan.klug at ideasonboard.com
Mon Aug 26 17:22:02 CEST 2024


Now, that the generic interpolator is available, use it to do the interpolation
of the lens shading tables. This makes the algorithm easier to read and remove
some duplicate code.

Signed-off-by: Stefan Klug <stefan.klug at ideasonboard.com>
---
 src/ipa/rkisp1/algorithms/lsc.cpp | 163 +++++++++---------------------
 src/ipa/rkisp1/algorithms/lsc.h   |  13 +--
 2 files changed, 57 insertions(+), 119 deletions(-)

diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp
index 161183fca352..7e0e65b22185 100644
--- a/src/ipa/rkisp1/algorithms/lsc.cpp
+++ b/src/ipa/rkisp1/algorithms/lsc.cpp
@@ -24,6 +24,34 @@
 
 namespace libcamera {
 
+namespace ipa {
+
+template<typename T>
+void interpolateVector(const std::vector<T> &a, const std::vector<T> &b,
+		       std::vector<T> &dest, double lambda)
+{
+	assert(a.size() == b.size());
+	dest.resize(a.size());
+	for (size_t i = 0; i < a.size(); i++) {
+		dest[i] = a[i] * (1.0 - lambda) + b[i] * lambda;
+	}
+}
+
+template<>
+void Interpolator<rkisp1::algorithms::LensShadingCorrection::Components>::
+	interpolate(const rkisp1::algorithms::LensShadingCorrection::Components &a,
+		    const rkisp1::algorithms::LensShadingCorrection::Components &b,
+		    rkisp1::algorithms::LensShadingCorrection::Components &dest,
+		    double lambda)
+{
+	interpolateVector(a.r, b.r, dest.r, lambda);
+	interpolateVector(a.gr, b.gr, dest.gr, lambda);
+	interpolateVector(a.gb, b.gb, dest.gb, lambda);
+	interpolateVector(a.b, b.b, dest.b, lambda);
+}
+
+} // namespace ipa
+
 namespace ipa::rkisp1::algorithms {
 
 /**
@@ -40,6 +68,8 @@ namespace ipa::rkisp1::algorithms {
 
 LOG_DEFINE_CATEGORY(RkISP1Lsc)
 
+constexpr int kColourTemperatureChangeThreshhold = 10;
+
 static std::vector<double> parseSizes(const YamlObject &tuningData,
 				      const char *prop)
 {
@@ -90,8 +120,9 @@ static std::vector<uint16_t> parseTable(const YamlObject &tuningData,
 }
 
 LensShadingCorrection::LensShadingCorrection()
-	: lastCt_({ 0, 0 })
+	: lastAppliedCt_(0), lastAppliedQuantizedCt_(0)
 {
+	sets_.setQuantization(kColourTemperatureChangeThreshhold);
 }
 
 /**
@@ -115,17 +146,18 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context,
 	}
 
 	const auto &sets = yamlSets.asList();
+	std::map<unsigned int, Components> lscData;
 	for (const auto &yamlSet : sets) {
 		uint32_t ct = yamlSet["ct"].get<uint32_t>(0);
 
-		if (sets_.count(ct)) {
+		if (lscData.count(ct)) {
 			LOG(RkISP1Lsc, Error)
 				<< "Multiple sets found for color temperature "
 				<< ct;
 			return -EINVAL;
 		}
 
-		Components &set = sets_[ct];
+		Components &set = lscData[ct];
 
 		set.ct = ct;
 		set.r = parseTable(yamlSet, "r");
@@ -142,11 +174,13 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context,
 		}
 	}
 
-	if (sets_.empty()) {
+	if (lscData.empty()) {
 		LOG(RkISP1Lsc, Error) << "Failed to load any sets";
 		return -EINVAL;
 	}
 
+	sets_.setData(std::move(lscData));
+
 	return 0;
 }
 
@@ -208,131 +242,34 @@ void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,
 	std::copy(set.b.begin(), set.b.end(), &config.b_data_tbl[0][0]);
 }
 
-/*
- * Interpolate LSC parameters based on color temperature value.
- */
-void LensShadingCorrection::interpolateTable(rkisp1_cif_isp_lsc_config &config,
-					     const Components &set0,
-					     const Components &set1,
-					     const uint32_t ct)
-{
-	double coeff0 = (set1.ct - ct) / static_cast<double>(set1.ct - set0.ct);
-	double coeff1 = (ct - set0.ct) / static_cast<double>(set1.ct - set0.ct);
-
-	for (unsigned int i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; ++i) {
-		for (unsigned int j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; ++j) {
-			unsigned int sample = i * RKISP1_CIF_ISP_LSC_SAMPLES_MAX + j;
-
-			config.r_data_tbl[i][j] =
-				set0.r[sample] * coeff0 +
-				set1.r[sample] * coeff1;
-
-			config.gr_data_tbl[i][j] =
-				set0.gr[sample] * coeff0 +
-				set1.gr[sample] * coeff1;
-
-			config.gb_data_tbl[i][j] =
-				set0.gb[sample] * coeff0 +
-				set1.gb[sample] * coeff1;
-
-			config.b_data_tbl[i][j] =
-				set0.b[sample] * coeff0 +
-				set1.b[sample] * coeff1;
-		}
-	}
-}
-
 /**
  * \copydoc libcamera::ipa::Algorithm::prepare
  */
 void LensShadingCorrection::prepare(IPAContext &context,
-				    const uint32_t frame,
+				    [[maybe_unused]] const uint32_t frame,
 				    [[maybe_unused]] IPAFrameContext &frameContext,
 				    rkisp1_params_cfg *params)
 {
 	struct rkisp1_cif_isp_lsc_config &config = params->others.lsc_config;
 
-	/*
-	 * If there is only one set, the configuration has already been done
-	 * for first frame.
-	 */
-	if (sets_.size() == 1 && frame > 0)
-		return;
-
-	/*
-	 * If there is only one set, pick it. We can ignore lastCt_, as it will
-	 * never be relevant.
-	 */
-	if (sets_.size() == 1) {
-		setParameters(params);
-		copyTable(config, sets_.cbegin()->second);
-		return;
-	}
-
 	uint32_t ct = context.activeState.awb.temperatureK;
-	ct = std::clamp(ct, sets_.cbegin()->first, sets_.crbegin()->first);
-
-	/*
-	 * If the original is the same, then it means the same adjustment would
-	 * be made. If the adjusted is the same, then it means that it's the
-	 * same as what was actually applied. Thus in these cases we can skip
-	 * reprogramming the LSC.
-	 *
-	 * original == adjusted can only happen if an interpolation
-	 * happened, or if original has an exact entry in sets_. This means
-	 * that if original != adjusted, then original was adjusted to
-	 * the nearest available entry in sets_, resulting in adjusted.
-	 * Clearly, any ct value that is in between original and adjusted
-	 * will be adjusted to the same adjusted value, so we can skip
-	 * reprogramming the LSC table.
-	 *
-	 * We also skip updating the original value, as the last one had a
-	 * larger bound and thus a larger range of ct values that will be
-	 * adjusted to the same adjusted.
-	 */
-	if ((lastCt_.original <= ct && ct <= lastCt_.adjusted) ||
-	    (lastCt_.adjusted <= ct && ct <= lastCt_.original))
+	if (std::abs(static_cast<int>(ct) - static_cast<int>(lastAppliedCt_)) <
+	    kColourTemperatureChangeThreshhold)
+		return;
+	unsigned int quantizedCt;
+	const Components &set = sets_.getInterpolated(ct, &quantizedCt);
+	if (lastAppliedQuantizedCt_ == quantizedCt)
 		return;
 
 	setParameters(params);
+	copyTable(config, set);
 
-	/*
-	 * The color temperature matches exactly one of the available LSC tables.
-	 */
-	if (sets_.count(ct)) {
-		copyTable(config, sets_[ct]);
-		lastCt_ = { ct, ct };
-		return;
-	}
+	lastAppliedCt_ = ct;
+	lastAppliedQuantizedCt_ = quantizedCt;
 
-	/* No shortcuts left; we need to round or interpolate */
-	auto iter = sets_.upper_bound(ct);
-	const Components &set1 = iter->second;
-	const Components &set0 = (--iter)->second;
-	uint32_t ct0 = set0.ct;
-	uint32_t ct1 = set1.ct;
-	uint32_t diff0 = ct - ct0;
-	uint32_t diff1 = ct1 - ct;
-	static constexpr double kThreshold = 0.1;
-	float threshold = kThreshold * (ct1 - ct0);
-
-	if (diff0 < threshold || diff1 < threshold) {
-		const Components &set = diff0 < diff1 ? set0 : set1;
-		LOG(RkISP1Lsc, Debug) << "using LSC table for " << set.ct;
-		copyTable(config, set);
-		lastCt_ = { ct, set.ct };
-		return;
-	}
-
-	/*
-	 * ct is not within 10% of the difference between the neighbouring
-	 * color temperatures, so we need to interpolate.
-	 */
 	LOG(RkISP1Lsc, Debug)
-		<< "ct is " << ct << ", interpolating between "
-		<< ct0 << " and " << ct1;
-	interpolateTable(config, set0, set1, ct);
-	lastCt_ = { ct, ct };
+		<< "ct is " << ct << ", quantized to "
+		<< quantizedCt;
 }
 
 REGISTER_IPA_ALGORITHM(LensShadingCorrection, "LensShadingCorrection")
diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h
index 5baf592797a6..4d0ec5575550 100644
--- a/src/ipa/rkisp1/algorithms/lsc.h
+++ b/src/ipa/rkisp1/algorithms/lsc.h
@@ -9,6 +9,8 @@
 
 #include <map>
 
+#include "libipa/interpolator.h"
+
 #include "algorithm.h"
 
 namespace libcamera {
@@ -27,7 +29,6 @@ public:
 		     IPAFrameContext &frameContext,
 		     rkisp1_params_cfg *params) override;
 
-private:
 	struct Components {
 		uint32_t ct;
 		std::vector<uint16_t> r;
@@ -36,23 +37,23 @@ private:
 		std::vector<uint16_t> b;
 	};
 
+private:
 	void setParameters(rkisp1_params_cfg *params);
 	void copyTable(rkisp1_cif_isp_lsc_config &config, const Components &set0);
 	void interpolateTable(rkisp1_cif_isp_lsc_config &config,
 			      const Components &set0, const Components &set1,
 			      const uint32_t ct);
 
-	std::map<uint32_t, Components> sets_;
+	ipa::Interpolator<Components> sets_;
 	std::vector<double> xSize_;
 	std::vector<double> ySize_;
 	uint16_t xGrad_[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE];
 	uint16_t yGrad_[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE];
 	uint16_t xSizes_[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE];
 	uint16_t ySizes_[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE];
-	struct {
-		uint32_t original;
-		uint32_t adjusted;
-	} lastCt_;
+
+	unsigned int lastAppliedCt_;
+	unsigned int lastAppliedQuantizedCt_;
 };
 
 } /* namespace ipa::rkisp1::algorithms */
-- 
2.43.0



More information about the libcamera-devel mailing list