From patchwork Wed Aug 5 16:13:10 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 27651 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 ED4AFC334C for ; Wed, 5 Aug 2026 16:14:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 704BB68186; Wed, 5 Aug 2026 18:14:00 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Y5U6sqLk"; 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 D25066816D for ; Wed, 5 Aug 2026 18:13:42 +0200 (CEST) Received: from [192.168.125.177] (mob-109-113-25-35.net.vodafone.it [109.113.25.35]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1D4B13A20; Wed, 5 Aug 2026 18:12:32 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1785946352; bh=0icdnYN3wJsMUHWBqdqovgOrFElVBnBhToX1Em0XrvE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Y5U6sqLkzVQiPDp/YFqKESF2pv1w1VFVt2/tYNy60JzAIhwslptoySUCEHOc/8KNu G95x1eJ3dk9iMALtkNepdg6XShQ+bg7DvutZHtdJs8928S25nrBXLEY9kd2lcrUQKd J31lMIPLB7qsPVDD0lmTp9RGJ9jzEkRkuLw8TJjM= From: Jacopo Mondi Date: Wed, 05 Aug 2026 18:13:10 +0200 Subject: [PATCH v7 28/32] ipa: libipa: lsc: Quantize gains in LscAlgorithm MIME-Version: 1.0 Message-Id: <20260805-libipa-algorithms-v7-28-7425b5b795d4@ideasonboard.com> References: <20260805-libipa-algorithms-v7-0-7425b5b795d4@ideasonboard.com> In-Reply-To: <20260805-libipa-algorithms-v7-0-7425b5b795d4@ideasonboard.com> To: libcamera-devel@lists.libcamera.org, Stefan Klug , Milan Zamazal Cc: Jacopo Mondi X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=22720; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=0icdnYN3wJsMUHWBqdqovgOrFElVBnBhToX1Em0XrvE=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBqc2Eiz0WxptMA3R8PH+5xCNItHtLe1QDsE6h4J BbiOkx3TwmJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCanNhIgAKCRByNAaPFqFW PGKyEADDLVscLnW2s4txMV3SEBCSSG0jo/SENjppPDym/sMwwr3/SokOupYcir+G4lElM260Mjn 7RRFrKeBqxE853PdkqDUyUelFg+zE/U1blpOsG4fiss7OjhFt0mooFFRR6j0CaTiGDGEVkpnKH8 rG5h7VRX/mxt2uxEGUUFWYsg/uP3xJNivBqQc/5pQkYcq8Qk4/zTk4dVNA/I6Vl8kNLpruPWL8L wDD4twq5qLznrcKtg80OLdPQKBzWc7SNKMR4C6z+bejSY/y65IuJ0hjAk6eQdpjCk9gJRHry0yf a9Otv9CVGxmrssGw9djQvJmEoo4bpqkhp5pb13grQi0gcL4AYKXZbsVAD9JzchubNqD0Socv4Mh EZv4riRLHo38TusStYKjbS52b2DCZ+BnzDMNC4Vbzq8ywx3PfYLWS8WcsQFtP4B1cv2e6qDc4cC xrz0U9B4jmMnKewGamyo6AiWS1FpIZHpaT9VCBKV3kGxb5CTOSD8DO69GKEOfI41l4GIvIOcgii upapCJUXot1x3iwrpQZUJwT1TeUCqb73ec5eifyEHQ3qcPUttHlSleJb/+hrtNckLM2AHKebg5q Hknr4EjQZ//NEpHuHpWyFEL7nId2jaLq2AjBno9F9BLbg7HnV2+Fe545iNqcJsUeofrsu3sYg0W KX/dZP7CMYdIhfw== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B 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" Template the LscAlgorithm class with the LSC engine register format and make lsc::Components<> parameteric on the type used to store the quantized LSC gains. This allows to quantize gains in the LscAlgorithm class and not in the IPA modules. Move the Components<> and ComponentsMap<> type to lsc.h in order for IPA modules to be able to access the quantized gains, and make the existing float-based Components internal to LscImplementation to be used as the exchange format between LscImplementation and LscAlgorithm. Split the LscAlgorithm class in two, one LscAlgorithmBase one for non-templated function implementations and one for the templated configure() implementation and for templated data members and accessor. Note that currently table-based LSC data do not require quantization as they're already expressed in register format in tuning files. This will change soon to make it easier to re-use LSC data between different platforms by expressing gains in floating point format in tuning files as well. Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- src/ipa/libipa/lsc.cpp | 134 +++++++++++++++++++++++++++++--------- src/ipa/libipa/lsc.h | 83 +++++++++++++++++++---- src/ipa/libipa/lsc_base.cpp | 75 +++++++++------------ src/ipa/libipa/lsc_base.h | 31 ++------- src/ipa/libipa/lsc_polynomial.cpp | 6 +- src/ipa/libipa/lsc_polynomial.h | 2 +- src/ipa/libipa/lsc_table.cpp | 2 +- src/ipa/libipa/lsc_table.h | 4 +- src/ipa/rkisp1/algorithms/lsc.cpp | 28 +++----- src/ipa/rkisp1/algorithms/lsc.h | 6 +- 10 files changed, 231 insertions(+), 140 deletions(-) diff --git a/src/ipa/libipa/lsc.cpp b/src/ipa/libipa/lsc.cpp index 8c5c28077cce..bb02290fc9ad 100644 --- a/src/ipa/libipa/lsc.cpp +++ b/src/ipa/libipa/lsc.cpp @@ -46,11 +46,91 @@ namespace lsc { * \brief Boolean flag for the LscAlgorithm updated status */ +/** + * \typedef Components + * \brief Associate colour components with a list of gains in register format + * \tparam T The type used to store the gain values + * + * LSC tables are defined as a list of gain values associated to a colour + * component. + * + * As different ISPs support different colour components (usually 'r', 'gr', + * 'gb', 'b' or just 'r', 'g', 'b') this class associates a string + * identifier for the colour component to a list of gains. + * + * Each key name shall match an entry in the tuning file. + * + * The list of keys is provided to the LscAlgorithm class using \a + * LscDescriptor::keys. + * + * The gain values are expressed in fixed-point register format stored in + * variabled of type \a T, as each platform potentially has a different register + * width. + */ + +/** + * \typedef ComponentsMap + * \brief Associate a colour temperature to a LSC table + * \tparam T The type of the gain values + * + * An LSC table is generated during the tuning phase for a specific colour + * temperature, and a tuning file usually contains LSC tables generated for + * several different colour temperatures. + */ + } /* namespace lsc */ +#ifndef __DOXYGEN__ +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 lsc::Components &a, + const lsc::Components &b, + lsc::Components &dest, + double lambda) +{ + for (auto const &[k, v] : a) + interpolateVector(v, b.at(k), dest[k], lambda); +} +#endif + +/** + * \class LscAlgorithmBase + * \brief Base class for LscAlgorithm + * + * Base class for LscAlgorithm for non-templated functions implementation + */ + +/** + * \var LscAlgorithmBase::impl_ + * \brief The LSC algorithm implementation + * + * There are two classes derived from LscImplementation, the LscTable and + * LscPolynomial ones. Which one to instantiate is decided by parsing the tuning + * file. + */ + +/** + * \var LscAlgorithmBase::polynomial_ + * \brief Boolean flag for polynomial LSC + * + * Set to true if polynomial LSC is in use. + */ + /** * \class LscAlgorithm * \brief libIPA LSC algorithm implementation + * \tparam U The platform fixed-point register format representation * * Due to the optical characteristics of the lens, the light intensity received * by the sensor is not uniform. The Lens Shading Correction algorithm applies @@ -192,6 +272,14 @@ namespace lsc { * * \todo Implement grid based re-sampling * + * After re-sampling, the LSC tables gain values are convereted from their + * floating point representation (LscImplementation::Components) to the + * platform's register representation (lsc::Components<>). Grid-based LSC tables + * currently already contain gains represented in register format, so no + * quantization is necessary but only a simple cast is required. + * + * \todo Express gains in floating point format for grid-based LSC tables + * * When the IPA algorithms wants to get access to the (re-sampled) tables to * program its LSC engine, it uses LscAlgorithm::interpolateComponents() to get * an LSC table interpolated by the LscAlgorithm class for the specified colour @@ -209,8 +297,8 @@ namespace lsc { * * \return 0 on success, a negative error code otherwise */ -int LscAlgorithm::init(const ValueNode &tuningData, ControlInfoMap::Map &controls, - const LscDescriptor &descriptor) +int LscAlgorithmBase::init(const ValueNode &tuningData, ControlInfoMap::Map &controls, + const LscDescriptor &descriptor) { polynomial_ = false; @@ -245,12 +333,15 @@ int LscAlgorithm::init(const ValueNode &tuningData, ControlInfoMap::Map &control } /** + * \fn LscAlgorithm::configure() + * \brief Re-sample and quantize LSC data * \param[in] state The LSC active state * \param[in] analogCrop The current sensor analog crop rectangle * \param[in] xPos List of horizontal positions of the LSC grid nodes * \param[in] yPos List of vertical positions of the LSC grid nodes * - * Re-sample the LSC data for an \a analogCrop. + * Re-sample the LSC data for an \a analogCrop and convert gains to their + * register representation using the class template paramter \a U. * * LSC tables are generated at tuning time using a known sensor configuration. * When a new streaming session is started, it might use a different sensor @@ -263,30 +354,12 @@ int LscAlgorithm::init(const ValueNode &tuningData, ControlInfoMap::Map &control * * \sa LscImplementation::sampleForCrop * + * Once tables have been re-sampled, they get quantized to the platform's + * fixed-point register representation using the LscAlgorithm template parameter + * \a U. + * * \return 0 on success, a negative error code otherwise */ -int LscAlgorithm::configure(lsc::ActiveState &state, const Rectangle &analogCrop, - const std::vector &xPos, - const std::vector &yPos) -{ - LOG(Lsc, Debug) << "Sample Lsc data for " << analogCrop; - lsc::ComponentsMap lscData = - impl_->sampleForCrop(analogCrop, xPos, yPos); - - /* - * Retain a copy of the components table. - * - * We could avoid a copy here if getComponents() could - * return sets_.data() but I wasn't able to work around the - * compiler refusing it. - */ - lscData_ = lscData; - - sets_.setData(std::move(lscData)); - state.enabled = true; - - return 0; -} /** * \brief Queue a request to the lsc algorithm @@ -297,9 +370,9 @@ int LscAlgorithm::configure(lsc::ActiveState &state, const Rectangle &analogCrop * Queue a new list of \a controls to the lsc algorithm. * The only supported control is controls::LensShadingCorrectionEnable. */ -void LscAlgorithm::queueRequest(lsc::ActiveState &state, - lsc::FrameContext &context, - const ControlList &controls) +void LscAlgorithmBase::queueRequest(lsc::ActiveState &state, + lsc::FrameContext &context, + const ControlList &controls) { const auto &lscEnable = controls.get(controls::LensShadingCorrectionEnable); if (lscEnable && *lscEnable != state.enabled) { @@ -322,7 +395,7 @@ void LscAlgorithm::queueRequest(lsc::ActiveState &state, * Populates the list of \a metadata with controls handled by the LscAlgorithm * class. The only supported metadata is controls::LensShadingCorrectionEnable. */ -void LscAlgorithm::process(lsc::FrameContext &context, ControlList &metadata) +void LscAlgorithmBase::process(lsc::FrameContext &context, ControlList &metadata) { metadata.set(controls::LensShadingCorrectionEnable, context.enabled); } @@ -350,8 +423,7 @@ void LscAlgorithm::process(lsc::FrameContext &context, ControlList &metadata) /** * \fn LscAlgorithm::getComponents - * - * Return the map of LSC data per-colour-temperature. + * \brief Return the map of LSC data per-colour-temperature * * Calling this function is only valid after LscAlgorithm::configure() has been * called. An empty components list is returned otherwise. diff --git a/src/ipa/libipa/lsc.h b/src/ipa/libipa/lsc.h index 9fe8ad67ea33..30330f284013 100644 --- a/src/ipa/libipa/lsc.h +++ b/src/ipa/libipa/lsc.h @@ -33,37 +33,96 @@ struct FrameContext { bool update; }; +template +using Components = std::map, std::less<>>; + +template +using ComponentsMap = std::map>; + } /* namespace lsc */ -class LscAlgorithm +#ifndef __DOXYGEN__ +template<> +void Interpolator>:: + interpolate(const lsc::Components &a, + const lsc::Components &b, + lsc::Components &dest, + double lambda); +#endif /* __DOXYGEN__ */ + +class LscAlgorithmBase { public: int init(const ValueNode &tuningData, ControlInfoMap::Map &controls, const LscDescriptor &descriptor); - int configure(lsc::ActiveState &state, const Rectangle &analogCrop, - const std::vector &xPos, - const std::vector &yPos); - void queueRequest(lsc::ActiveState &state, lsc::FrameContext &context, const ControlList &controls); void process(lsc::FrameContext &context, ControlList &metadata); - const lsc::Components interpolateComponents(unsigned int ct) +protected: + LscAlgorithmBase() = default; + + std::unique_ptr impl_; + bool polynomial_; +}; + +template +class LscAlgorithm : public LscAlgorithmBase +{ +private: + using Components = lsc::Components; + using ComponentsMap = lsc::ComponentsMap; + +public: + LscAlgorithm() = default; + + int configure(lsc::ActiveState &state, const Rectangle &analogCrop, + const std::vector &xPos, + const std::vector &yPos) + { + LscImplementation::ComponentsMap data = + impl_->sampleForCrop(analogCrop, xPos, yPos); + + ComponentsMap lscData; + for (const auto &[t, c] : data) { + Components &comp = lscData[t]; + + for (const auto &[k, gains] : c) { + auto &quantizedGains = comp[k]; + quantizedGains.reserve(gains.size()); + + for (const float &gain : gains) { + /* + * Tabular LSC tables already store + * quantized values. + */ + if (polynomial_) + quantizedGains.push_back(U(gain).quantized()); + else + quantizedGains.push_back(gain); + } + } + } + + sets_.setData(std::move(lscData)); + state.enabled = true; + + return 0; + } + + const Components interpolateComponents(unsigned int ct) { return sets_.getInterpolated(ct); } - const lsc::ComponentsMap getComponents() + const ComponentsMap &getComponents() const { - return lscData_; + return sets_.data(); } private: - std::unique_ptr impl_; - Interpolator sets_; - lsc::ComponentsMap lscData_; - bool polynomial_; + Interpolator sets_; }; } /* namespace ipa */ diff --git a/src/ipa/libipa/lsc_base.cpp b/src/ipa/libipa/lsc_base.cpp index cb770f164d53..baf25df6b908 100644 --- a/src/ipa/libipa/lsc_base.cpp +++ b/src/ipa/libipa/lsc_base.cpp @@ -16,49 +16,6 @@ namespace libcamera { namespace ipa { -namespace lsc { - -/** - * \typedef Components - * \brief Associate colour components with a list of gains - * - * LSC tables are defined as a list of gain values associated to a colour - * component. - * - * As different ISPs support different colour components (usually 'r', 'gr', - * 'gb', 'b' or just 'r', 'g', 'b') this class associates a string - * identifier for the colour component to a list of gains. - * - * Each key name shall match an entry in the tuning file. - * - * The list of keys is provided to the LscAlgorithm class using \a - * LscDescriptor::keys. - */ - -/** - * \typedef ComponentsMap - * \brief Associate a colour temperature to a LSC table - * - * An LSC table is generated during the tuning phase for a specific colour - * temperature, and a tuning file usually contains LSC tables generated for - * several different colour temperatures. - */ - -} /* namespace lsc */ - -#ifndef __DOXYGEN__ -template<> -void Interpolator:: - interpolate(const lsc::Components &a, - const lsc::Components &b, - lsc::Components &dest, - double lambda) -{ - for (auto const &[k, v] : a) - interpolateVector(v, b.at(k), dest[k], lambda); -} -#endif - /** * \struct LscDescriptor * \brief Describe the ISP LSC engine @@ -90,6 +47,38 @@ void Interpolator:: * Defines the interface for the LSC algorithm implementation. */ +/** + * \typedef LscImplementation::Components + * \brief Associate colour components with a list of gains in float format + * + * LSC tables are defined as a list of gain values associated to a colour + * component. + * + * As different ISP support different colour components (usually 'r', 'gr', + * 'gb', 'b' or just 'r', 'g', 'b') this class associates a string + * identifier for the colour component to a list of gains. + * + * The gain values are represented as floats and are either loaded from tuning + * file or are the result of a polynomial expansion, depending on the + * LscImplementation derived class in use (LscTable or LscPolynomial). + * + * The gain values are converted to the platform's register format before being + * returned to the IPA module by LscAlgorithm::configure(). + * + * \todo Tabular LSC data are already expressed in register format. Make the + * tuning files express gains in float format as well and actually perform + * quantization in LscAlgorithm::configure(). + */ + +/** + * \typedef LscImplementation::ComponentsMap + * \brief Associate a colour temperature to a LSC table + * + * An LSC table is generated during the tuning phase for a specific colour + * temperature, and a tuning file usually contains LSC tables generated for + * several different colour temperatures. + */ + /** * \fn LscImplementation::~LscImplementation * \brief Virtual class destructor diff --git a/src/ipa/libipa/lsc_base.h b/src/ipa/libipa/lsc_base.h index 2cff34b32a2b..d53736cb71d3 100644 --- a/src/ipa/libipa/lsc_base.h +++ b/src/ipa/libipa/lsc_base.h @@ -24,32 +24,6 @@ namespace libcamera { namespace ipa { -namespace lsc { - -using Components = std::map, std::less<>>; -using ComponentsMap = std::map; - -} /* namespace lsc */ - -#ifndef __DOXYGEN__ -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 lsc::Components &a, - const lsc::Components &b, - lsc::Components &dest, - double lambda); -#endif /* __DOXYGEN__ */ - struct LscDescriptor { std::vector keys; unsigned int numHSamples; @@ -60,12 +34,15 @@ struct LscDescriptor { class LscImplementation { public: + using Components = std::map, std::less<>>; + using ComponentsMap = std::map; + virtual ~LscImplementation() {} virtual int parseLscData(const ValueNode &tuningData, const LscDescriptor &descriptor) = 0; - virtual lsc::ComponentsMap + virtual ComponentsMap sampleForCrop(const Rectangle &cropRectangle, std::vector xPos, std::vector yPos) = 0; }; diff --git a/src/ipa/libipa/lsc_polynomial.cpp b/src/ipa/libipa/lsc_polynomial.cpp index 419de2c12cf0..6c38c7f7eeb1 100644 --- a/src/ipa/libipa/lsc_polynomial.cpp +++ b/src/ipa/libipa/lsc_polynomial.cpp @@ -194,15 +194,15 @@ int LscPolynomial::parseLscData(const ValueNode &sets, * [0, 0.0625, 0.125, 0.1875, ... , 1]. It is expected that the first position * is 0 and the last position is 1. */ -lsc::ComponentsMap +LscImplementation::ComponentsMap LscPolynomial::sampleForCrop(const Rectangle &cropRectangle, std::vector xPos, std::vector yPos) { - lsc::ComponentsMap components; + LscImplementation::ComponentsMap components; for (const auto &[t, c] : lscData_) { - lsc::Components &comp = components[t]; + LscImplementation::Components &comp = components[t]; for (const auto &[k, p] : c) comp.try_emplace(k, samplePolynomial(p, xPos, yPos, diff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h index 24b216a1aa25..b9d3d834662b 100644 --- a/src/ipa/libipa/lsc_polynomial.h +++ b/src/ipa/libipa/lsc_polynomial.h @@ -60,7 +60,7 @@ public: int parseLscData(const ValueNode &sets, const LscDescriptor &descriptor) override; - lsc::ComponentsMap + LscImplementation::ComponentsMap sampleForCrop(const Rectangle &cropRectangle, std::vector xPos, std::vector yPos) override; diff --git a/src/ipa/libipa/lsc_table.cpp b/src/ipa/libipa/lsc_table.cpp index 3e8b1a060ce7..74ea8a7266e1 100644 --- a/src/ipa/libipa/lsc_table.cpp +++ b/src/ipa/libipa/lsc_table.cpp @@ -59,7 +59,7 @@ int LscTable::parseLscData(const ValueNode &sets, int LscTable::parseLscComponent(const ValueNode &yamlSet, unsigned int ct, const LscDescriptor &descriptor) { - lsc::Components component; + LscImplementation::Components component; for (auto &k : descriptor.keys) { auto [it, inserted] = component.try_emplace(k, parseTable(yamlSet, diff --git a/src/ipa/libipa/lsc_table.h b/src/ipa/libipa/lsc_table.h index 6d9b0c692b7f..9f39b38e258c 100644 --- a/src/ipa/libipa/lsc_table.h +++ b/src/ipa/libipa/lsc_table.h @@ -29,7 +29,7 @@ public: int parseLscData(const ValueNode &sets, const LscDescriptor &descriptor) override; - lsc::ComponentsMap + LscImplementation::ComponentsMap sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle, [[maybe_unused]] std::vector xPos, [[maybe_unused]] std::vector yPos) override @@ -47,7 +47,7 @@ private: unsigned int numHSamples, unsigned int numVSamples); - lsc::ComponentsMap lscData_; + LscImplementation::ComponentsMap lscData_; }; } /* namespace ipa */ diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 911ac6895a14..f2858656023e 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -175,23 +175,16 @@ void LensShadingCorrection::setParameters(rkisp1_cif_isp_lsc_config &config) } void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config, - const lsc::Components &set) + const lsc::Components &set) { - /* - * The hardware uses 2.10 fixed point format and limits the legal values - * to [1..3.999]. Scale and clamp the sampled values accordingly. - */ - const auto quantizeSet = [&](const std::string &key, uint16_t *dst) { - const auto &s = set.at(key); - std::transform(s.begin(), s.end(), dst, [](float f) { - return std::clamp(f * 1024, 1024, 4095); - }); - }; - - quantizeSet("r", &config.r_data_tbl[0][0]); - quantizeSet("gr", &config.gr_data_tbl[0][0]); - quantizeSet("gb", &config.gb_data_tbl[0][0]); - quantizeSet("b", &config.b_data_tbl[0][0]); + const auto &r = set.at("r"); + std::copy(r.begin(), r.end(), &config.r_data_tbl[0][0]); + const auto &gr = set.at("gr"); + std::copy(gr.begin(), gr.end(), &config.gr_data_tbl[0][0]); + const auto &gb = set.at("gb"); + std::copy(gb.begin(), gb.end(), &config.gb_data_tbl[0][0]); + const auto &b = set.at("b"); + std::copy(b.begin(), b.end(), &config.b_data_tbl[0][0]); } /** @@ -241,8 +234,7 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context, setParameters(*config); - const lsc::Components &set = lscAlgo_.interpolateComponents(quantizedCt); - copyTable(*config, set); + copyTable(*config, lscAlgo_.interpolateComponents(quantizedCt)); lastAppliedCt_ = ct; lastAppliedQuantizedCt_ = quantizedCt; diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h index 63f0887f0838..c1f8904426c0 100644 --- a/src/ipa/rkisp1/algorithms/lsc.h +++ b/src/ipa/rkisp1/algorithms/lsc.h @@ -12,6 +12,7 @@ #include #include "libcamera/internal/value_node.h" +#include "libipa/fixedpoint.h" #include "libipa/lsc.h" @@ -41,7 +42,8 @@ public: ControlList &metadata) override; private: void setParameters(rkisp1_cif_isp_lsc_config &config); - void copyTable(rkisp1_cif_isp_lsc_config &config, const lsc::Components &set0); + void copyTable(rkisp1_cif_isp_lsc_config &config, + const lsc::Components &set); std::vector xSize_; std::vector ySize_; @@ -55,7 +57,7 @@ private: unsigned int lastAppliedCt_; unsigned int lastAppliedQuantizedCt_; - LscAlgorithm lscAlgo_; + LscAlgorithm> lscAlgo_; }; } /* namespace ipa::rkisp1::algorithms */