[PATCH v3 5/9] ipa: rkisp1: Use interpolator in lsc
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Mon Sep 23 22:44:58 CEST 2024
On Fri, Sep 20, 2024 at 03:39:20PM +0200, Stefan Klug wrote:
> 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>
> Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> Reviewed-by: Paul Elder <paul.elder at ideasonboard.com>
>
> ---
>
> Changes in v3:
> - Collected tags
> - Fixed a comment
> ---
> src/ipa/rkisp1/algorithms/lsc.cpp | 166 +++++++++---------------------
> src/ipa/rkisp1/algorithms/lsc.h | 13 +--
> 2 files changed, 57 insertions(+), 122 deletions(-)
>
> diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp
> index 5f3a0388075b..fe84062bbc70 100644
> --- a/src/ipa/rkisp1/algorithms/lsc.cpp
> +++ b/src/ipa/rkisp1/algorithms/lsc.cpp
> @@ -24,6 +24,36 @@
>
> namespace libcamera {
>
> +namespace ipa {
> +
> +constexpr int kColourTemperatureChangeThreshhold = 10;
> +
> +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());
Use ASSERT(), not assert(). Same for the whole patch series.
> + dest.resize(a.size());
> + for (size_t i = 0; i < a.size(); i++) {
> + dest[i] = a[i] * (1.0 - lambda) + b[i] * lambda;
> + }
No need for curly braces.
> +}
> +
> +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);
> +}
Sounds like there may be an opportunity to refactor the Components
structure, but that's probably for later.
> +
> +} /* namespace ipa */
> +
> namespace ipa::rkisp1::algorithms {
>
> /**
> @@ -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;
> }
>
> @@ -202,134 +236,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,
> RkISP1Params *params)
> {
> - /*
> - * 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) {
> - auto config = params->block<BlockType::Lsc>();
> - config.setEnabled(true);
> -
> - setParameters(*config);
> - 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;
>
> auto config = params->block<BlockType::Lsc>();
> config.setEnabled(true);
> setParameters(*config);
> + 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 a9c7a230e0fc..5a0824e36dd5 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,
> RkISP1Params *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_cif_isp_lsc_config &config);
> 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 */
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list