From patchwork Fri Sep 20 13:39:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 21300 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 668DFC32D6 for ; Fri, 20 Sep 2024 13:40:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A582C63502; Fri, 20 Sep 2024 15:40:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="JakXYiga"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4912A634F5 for ; Fri, 20 Sep 2024 15:40:00 +0200 (CEST) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:8ade:938d:48b1:cede]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4CAB7C62; Fri, 20 Sep 2024 15:38:36 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1726839516; bh=fltO5fWWoE7ngxCRHIGb+I6vpcCv3x6w1DV77Fxtpdo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JakXYigahThuIQW/WFv2zk8gjjTP9QqF+PF2Xs+9urgbW7Gx6/3LC2H+t2KL5qP+h Zcvm3HHwDAou6cn+Znptb991r6L8f5Pb3iZBwT/iCblh+/9rzL25nWqtV2SGqLzitS nKuZOFcErodzJUZTknqbSl4m+h66CyAAeJPhqjm4= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , Kieran Bingham , Paul Elder Subject: [PATCH v3 5/9] ipa: rkisp1: Use interpolator in lsc Date: Fri, 20 Sep 2024 15:39:20 +0200 Message-ID: <20240920133941.90629-6-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240920133941.90629-1-stefan.klug@ideasonboard.com> References: <20240920133941.90629-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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 Reviewed-by: Kieran Bingham Reviewed-by: Paul Elder --- 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 +void interpolateVector(const std::vector &a, const std::vector &b, + std::vector &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:: + 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 { /** @@ -90,8 +120,9 @@ static std::vector 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 lscData; for (const auto &yamlSet : sets) { uint32_t ct = yamlSet["ct"].get(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(set1.ct - set0.ct); - double coeff1 = (ct - set0.ct) / static_cast(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(); - 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(ct) - static_cast(lastAppliedCt_)) < + kColourTemperatureChangeThreshhold) + return; + unsigned int quantizedCt; + const Components &set = sets_.getInterpolated(ct, &quantizedCt); + if (lastAppliedQuantizedCt_ == quantizedCt) return; auto config = params->block(); 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 +#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 r; @@ -36,23 +37,23 @@ private: std::vector 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 sets_; + ipa::Interpolator sets_; std::vector xSize_; std::vector 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 */