Show a patch.

GET /api/patches/27231/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 27231,
    "url": "https://patchwork.libcamera.org/api/patches/27231/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/27231/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20260706-libipa-algorithms-v3-31-968757b038bb@ideasonboard.com>",
    "date": "2026-07-06T08:01:51",
    "name": "[v3,31/35] ipa: libipa: lsc: Template lsc::Components",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "1141610d0a0fd3d609cd662db9378c70e939aad2",
    "submitter": {
        "id": 143,
        "url": "https://patchwork.libcamera.org/api/people/143/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo.mondi@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/27231/mbox/",
    "series": [
        {
            "id": 6038,
            "url": "https://patchwork.libcamera.org/api/series/6038/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=6038",
            "date": "2026-07-06T08:01:20",
            "name": "ipa: libipa: Introduce libipa algorithms",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/6038/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/27231/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/27231/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 2BDF0C330F\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  6 Jul 2026 08:02:39 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A95116605D;\n\tMon,  6 Jul 2026 10:02:38 +0200 (CEST)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 96CEB66047\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  6 Jul 2026 10:02:18 +0200 (CEST)",
            "from [192.168.125.177] (mob-109-113-60-81.net.vodafone.it\n\t[109.113.60.81])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 73031226E;\n\tMon,  6 Jul 2026 10:01:29 +0200 (CEST)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"oFqWly+J\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1783324890;\n\tbh=3KIg97egNK9A9fKHvykVfRGsaB2SQbUBinIuZuNuJfo=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=oFqWly+JexaSG3IDqI4O7PqM9YhCgD6yyu5cK1I7Eaef8z6cfRiLBAvED2Ar6toR1\n\tSXYnysM4pTDB6rKyn9FNjLiC5g8X+vEZ6d9rye0z9J0NqyS8T75jmoOj2femICut67\n\tJVaqXY1DluwpksBXQP/QkBGZEjDJ2zXDNL/0XbSg=",
        "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "Date": "Mon, 06 Jul 2026 10:01:51 +0200",
        "Subject": "[PATCH v3 31/35] ipa: libipa: lsc: Template lsc::Components",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "7bit",
        "Message-Id": "<20260706-libipa-algorithms-v3-31-968757b038bb@ideasonboard.com>",
        "References": "<20260706-libipa-algorithms-v3-0-968757b038bb@ideasonboard.com>",
        "In-Reply-To": "<20260706-libipa-algorithms-v3-0-968757b038bb@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org, \n\tStefan Klug <stefan.klug@ideasonboard.com>",
        "Cc": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "X-Mailer": "b4 0.14.3",
        "X-Developer-Signature": "v=1; a=openpgp-sha256; l=16122;\n\ti=jacopo.mondi@ideasonboard.com; h=from:subject:message-id;\n\tbh=3KIg97egNK9A9fKHvykVfRGsaB2SQbUBinIuZuNuJfo=;\n\tb=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBqS2Dyy9Oihpw94fqFMmhJU9oQjbL43I78MZjOB\n\t26PQHSadz2JAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaktg8gAKCRByNAaPFqFW\n\tPOuPD/oDSbJsGX5SwbPBU4xNicL8FLUg9csVwO1KG38ugw3RVv+E33vLnhrmcjQwoC4+6Ns91th\n\terT9Xv+/jn3abW9wzfzC74XdGZtzP78aIeWOQRgI8wR2ZzwnuIxVwrirXeriG7pa83ijNkQ9SSw\n\tnaV9bFqK1gsZv27oZKRSFeP8bZFWC4MDDMYuFs0AT4b2onSSbCM4UKm8Tw7lApuk8JXXWs4/3aC\n\tVo2oTiCHpXfPwEqTdsNozUFU2oZK8Wgruv+PcYo9cmWdqvVByVVoX1tKvk1vA6UfEJWFW68dyep\n\t5vHvlOfl92dPyDHUjVyYJdzrKhTOipIXWtbvKUdi9CkT3tkPlWH2hw3IFsv5GckFgO8Uav7Avp9\n\tIUCb5h2ayB45EbLnfgyYA/B8wKTDV5S+v2exitDT8olg/TthyxGf29/f7J7mjISEUs4onw1ZJaP\n\temXnLNYv44KMP/JLtRuMoxJx5ds5W5wytY/84wqn6+A4FKhOJfN/I1k9YHJHqhH11w0pa9nE6+j\n\tdIf4TdhxkH2QnJPHYQWNbXsgWRc2zDYABHubJMuKon4LBW/jBcHq02+1aUGxL/rMUAGNH1gH5Ct\n\tnqNXMTTKhj//UtDGa82thVrNxKS868jpFjV0rqocSSo3nQOpHvA1GW+Jpi1NjsR6dCv3ulm6Z7E\n\thCqY2IzL85DJqwg==",
        "X-Developer-Key": "i=jacopo.mondi@ideasonboard.com; a=openpgp;\n\tfpr=72392EDC88144A65C701EA9BA5826A2587AD026B",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "The lsc::Component type maps a string that identifies a colour channel\nto a vector of gains expressed in register format.\n\nThe current implementation assumes gains in u16 format which matches the\nRkISP1 register format.\n\nAs lsc::Components is used both to store gains as loaded from tuning\nfile and the result of the radial polynomial expansion, different ISP\nuse different bit widths to represent the gain values.\n\nTemplate the lsc::Components and lsc::ComponentsMap with the type used\nto store the gain values.\n\nUse the Quantized::QuantizedType typedef which expresses the\ninteger type required to store all bits of the fixed point number\nused to instantiate LscAlgorithm<> by the IPA module to template\nComponents<>.\n\nThe LscTable class now requires to inline all tuning file parsing\nhelpers, so we can drop the just introduced LscTableBase.\n\nSpecialize Interpolator<lsc::Components<>> for uint16_t as this is the\nformat used by RkISP1.\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n src/ipa/libipa/lsc.h              |  13 +++--\n src/ipa/libipa/lsc_base.cpp       |  19 +++++---\n src/ipa/libipa/lsc_base.h         |  21 +++++---\n src/ipa/libipa/lsc_polynomial.h   |  19 +++++---\n src/ipa/libipa/lsc_table.cpp      | 100 +++-----------------------------------\n src/ipa/libipa/lsc_table.h        |  90 ++++++++++++++++++++++++++--------\n src/ipa/rkisp1/algorithms/lsc.cpp |   4 +-\n src/ipa/rkisp1/algorithms/lsc.h   |   3 +-\n 8 files changed, 125 insertions(+), 144 deletions(-)",
    "diff": "diff --git a/src/ipa/libipa/lsc.h b/src/ipa/libipa/lsc.h\nindex d48336b169f4..6dc76b6572b3 100644\n--- a/src/ipa/libipa/lsc.h\n+++ b/src/ipa/libipa/lsc.h\n@@ -53,6 +53,9 @@ public:\n template<typename U>\n class LscAlgorithm : public LscAlgorithmBase\n {\n+private:\n+\tusing T = typename U::QuantizedType;\n+\n public:\n \tint init(const ValueNode &tuningData, ControlInfoMap::Map &controls,\n \t\t const LscDescriptor &descriptor)\n@@ -94,7 +97,7 @@ public:\n \t\t      const std::vector<double> &yPos)\n \t{\n \t\tLOG(Lsc, Debug) << \"Sample Lsc data for \" << analogCrop;\n-\t\tlsc::ComponentsMap lscData =\n+\t\tlsc::ComponentsMap<T> lscData =\n \t\t\timpl_->sampleForCrop(analogCrop, xPos, yPos);\n \n \t\t/*\n@@ -112,20 +115,20 @@ public:\n \t\treturn 0;\n \t}\n \n-\tconst lsc::Components interpolateComponents(unsigned int ct)\n+\tconst lsc::Components<T> interpolateComponents(unsigned int ct)\n \t{\n \t\treturn sets_.getInterpolated(ct);\n \t}\n \n-\tconst lsc::ComponentsMap getComponents()\n+\tconst lsc::ComponentsMap<T> getComponents()\n \t{\n \t\treturn lscData_;\n \t}\n \n private:\n \tstd::unique_ptr<LscImplementation<U>> impl_;\n-\tInterpolator<lsc::Components> sets_;\n-\tlsc::ComponentsMap lscData_;\n+\tInterpolator<lsc::Components<T>> sets_;\n+\tlsc::ComponentsMap<T> lscData_;\n \tbool polynomial_;\n };\n \ndiff --git a/src/ipa/libipa/lsc_base.cpp b/src/ipa/libipa/lsc_base.cpp\nindex 0c3a10d25cf8..ff5d47e85c01 100644\n--- a/src/ipa/libipa/lsc_base.cpp\n+++ b/src/ipa/libipa/lsc_base.cpp\n@@ -32,25 +32,28 @@ namespace ipa {\n namespace lsc {\n \n /**\n- * \\typedef Components\n+ * \\class Components\n  * \\brief Associate a colour components with a list of gains\n+ * \\tparam T The type used to store the gain values when loaded from tuning file\n  *\n  * Lsc tables are defined as a list of gain values associated to a colour\n  * component.\n  *\n  * As different ISP support different colour components (usually 'r', 'gr',\n  * 'gb', 'b' or just 'r', 'g', 'b') this class associates a string\n- * identifier for the colour component to a list of gains.\n+ * identifier for the colour component to a list of gains of type \\a T.\n  *\n- * Each key name shall match an entry in the tuning file.\n+ * Each key name shall match an entry in the tuning file and the type \\a T\n+ * shall match the size of the registers where gains are stored.\n  *\n  * The list of keys is provided to the LscAlgorithm class using \\a\n  * LscDescriptor::keys.\n  */\n \n /**\n- * \\typedef ComponentsMap\n+ * \\class ComponentsMap\n  * \\brief Associate a colour temperature to a lsc table\n+ * \\tparam T The type used to store the gain values when loaded from tuning file\n  *\n  * An lsc table is generated during the tuning phase for a specific light\n  * temperature, and a tuning file usually contains lsc tables generated for\n@@ -61,10 +64,10 @@ namespace lsc {\n \n #ifndef __DOXYGEN__\n template<>\n-void Interpolator<lsc::Components>::\n-\tinterpolate(const lsc::Components &a,\n-\t\t    const lsc::Components &b,\n-\t\t    lsc::Components &dest,\n+void Interpolator<lsc::Components<uint16_t>>::\n+\tinterpolate(const lsc::Components<uint16_t> &a,\n+\t\t    const lsc::Components<uint16_t> &b,\n+\t\t    lsc::Components<uint16_t> &dest,\n \t\t    double lambda)\n {\n \tfor (auto const &[k, v] : a)\ndiff --git a/src/ipa/libipa/lsc_base.h b/src/ipa/libipa/lsc_base.h\nindex 721fd137ef21..4edcb2637d1b 100644\n--- a/src/ipa/libipa/lsc_base.h\n+++ b/src/ipa/libipa/lsc_base.h\n@@ -26,8 +26,15 @@ namespace ipa {\n \n namespace lsc {\n \n-using Components = std::map<std::string, std::vector<uint16_t>>;\n-using ComponentsMap = std::map<unsigned int, Components>;\n+template<typename T>\n+class Components : public std::map<std::string, std::vector<T>>\n+{\n+};\n+\n+template<typename T>\n+class ComponentsMap : public std::map<unsigned int, Components<T>>\n+{\n+};\n \n } /* namespace lsc */\n \n@@ -43,10 +50,10 @@ void interpolateVector(const std::vector<T> &a, const std::vector<T> &b,\n }\n \n template<>\n-void Interpolator<lsc::Components>::\n-\tinterpolate(const lsc::Components &a,\n-\t\t    const lsc::Components &b,\n-\t\t    lsc::Components &dest,\n+void Interpolator<lsc::Components<uint16_t>>::\n+\tinterpolate(const lsc::Components<uint16_t> &a,\n+\t\t    const lsc::Components<uint16_t> &b,\n+\t\t    lsc::Components<uint16_t> &dest,\n \t\t    double lambda);\n #endif /* __DOXYGEN__ */\n \n@@ -66,7 +73,7 @@ public:\n \tvirtual int parseLscData(const ValueNode &tuningData,\n \t\t\t\t const LscDescriptor &descriptor) = 0;\n \n-\tvirtual lsc::ComponentsMap\n+\tvirtual lsc::ComponentsMap<typename U::QuantizedType>\n \tsampleForCrop(const Rectangle &cropRectangle,\n \t\t      std::vector<double> xPos, std::vector<double> yPos);\n };\ndiff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h\nindex 04d7465b3af0..a84a736734e1 100644\n--- a/src/ipa/libipa/lsc_polynomial.h\n+++ b/src/ipa/libipa/lsc_polynomial.h\n@@ -67,6 +67,9 @@ protected:\n template<typename U>\n class LscPolynomial : public LscPolynomialBase, public LscImplementation<U>\n {\n+private:\n+\tusing T = typename U::QuantizedType;\n+\n public:\n \tint parseLscData(const ValueNode &yamlSets,\n \t\t\t const LscDescriptor &descriptor) override\n@@ -74,14 +77,14 @@ public:\n \t\treturn LscPolynomialBase::parseLscData(yamlSets, descriptor);\n \t}\n \n-\tlsc::ComponentsMap\n+\tlsc::ComponentsMap<T>\n \tsampleForCrop(const Rectangle &cropRectangle,\n \t\t      std::vector<double> xPos, std::vector<double> yPos) override\n \t{\n-\t\tlsc::ComponentsMap components;\n+\t\tlsc::ComponentsMap<T> components;\n \n \t\tfor (const auto &[t, c] : lscData_) {\n-\t\t\tlsc::Components comp;\n+\t\t\tlsc::Components<T> comp;\n \n \t\t\tfor (const auto &[k, p] : c) {\n \t\t\t\tcomp.emplace(std::piecewise_construct,\n@@ -97,17 +100,17 @@ public:\n \t}\n \n private:\n-\tstd::vector<uint16_t> samplePolynomial(const lsc::Polynomial &poly,\n-\t\t\t\t\t       Span<const double> xPositions,\n-\t\t\t\t\t       Span<const double> yPositions,\n-\t\t\t\t\t       const Rectangle &cropRectangle)\n+\tstd::vector<T> samplePolynomial(const lsc::Polynomial &poly,\n+\t\t\t\t\tSpan<const double> xPositions,\n+\t\t\t\t\tSpan<const double> yPositions,\n+\t\t\t\t\tconst Rectangle &cropRectangle)\n \t{\n \t\tdouble m = poly.getM();\n \t\tdouble x0 = cropRectangle.x / m;\n \t\tdouble y0 = cropRectangle.y / m;\n \t\tdouble w = cropRectangle.width / m;\n \t\tdouble h = cropRectangle.height / m;\n-\t\tstd::vector<uint16_t> samples;\n+\t\tstd::vector<T> samples;\n \n \t\tsamples.reserve(xPositions.size() * yPositions.size());\n \ndiff --git a/src/ipa/libipa/lsc_table.cpp b/src/ipa/libipa/lsc_table.cpp\nindex bb3c76b12332..aa391534335e 100644\n--- a/src/ipa/libipa/lsc_table.cpp\n+++ b/src/ipa/libipa/lsc_table.cpp\n@@ -13,99 +13,6 @@ LOG_DEFINE_CATEGORY(LscTable)\n \n namespace ipa {\n \n-/**\n- * \\class LscTableBase\n- * \\brief Base class for LscTable\n- *\n- * Base class for LscTable for non-templated functions.\n- */\n-\n-/**\n- * \\brief Parse tabular lsc data\n- * \\param[in] sets The tuning file content\n- * \\param[in] descriptor The lsc engine descriptor\n- *\n- * Parse the lsc data in tabular form from the \\a sets tuning data.\n- *\n- * \\return 0 on success or a negative error number otherwise\n- */\n-int LscTableBase::parseLscData(const ValueNode &sets,\n-\t\t\t       const LscDescriptor &descriptor)\n-{\n-\tfor (const auto &set : sets.asList()) {\n-\t\tuint32_t ct = set[\"ct\"].get<uint32_t>(0);\n-\n-\t\tint ret = parseLscComponent(set, ct, descriptor);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\t}\n-\n-\tif (lscData_.empty()) {\n-\t\tLOG(LscTable, Error) << \"Failed to load any sets\";\n-\t\treturn -EINVAL;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-int LscTableBase::parseLscComponent(const ValueNode &yamlSet,\n-\t\t\t\t    unsigned int ct, const LscDescriptor &descriptor)\n-{\n-\tlsc::Components component;\n-\tfor (auto &k : descriptor.keys) {\n-\t\tauto [it, inserted] = component.emplace(\n-\t\t\tstd::piecewise_construct,\n-\t\t\tstd::forward_as_tuple(k.c_str()),\n-\t\t\tstd::forward_as_tuple(parseTable(yamlSet,\n-\t\t\t\t\t\t\t k.c_str(),\n-\t\t\t\t\t\t\t descriptor.numHCells,\n-\t\t\t\t\t\t\t descriptor.numVCells)));\n-\t\tif (!inserted || it->second.empty()) {\n-\t\t\tLOG(LscTable, Error)\n-\t\t\t\t<< \"Set \" << k << \" for color temperature \"\n-\t\t\t\t<< ct << \" is missing\";\n-\t\t\treturn -EINVAL;\n-\t\t}\n-\t}\n-\n-\tauto [it, inserted] = lscData_.emplace(ct, component);\n-\tif (!inserted) {\n-\t\tLOG(LscTable, Error)\n-\t\t\t<< \"Multiple sets found for color temperature \"\n-\t\t\t<< ct;\n-\t\treturn -EINVAL;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-std::vector<uint16_t> LscTableBase::parseTable(const ValueNode &tuningData,\n-\t\t\t\t\t       const char *prop,\n-\t\t\t\t\t       unsigned int numHCells,\n-\t\t\t\t\t       unsigned int numVCells)\n-{\n-\tunsigned int lscNumSamples = numHCells * numVCells;\n-\n-\tstd::vector<uint16_t> table =\n-\t\ttuningData[prop].get<std::vector<uint16_t>>().value_or(utils::defopt);\n-\tif (table.size() != lscNumSamples) {\n-\t\tLOG(LscTable, Error)\n-\t\t\t<< \"Invalid '\" << prop << \"' values: expected \"\n-\t\t\t<< lscNumSamples\n-\t\t\t<< \" elements, got \" << table.size();\n-\t\treturn {};\n-\t}\n-\n-\treturn table;\n-}\n-\n-/**\n- * \\var LscTableBase::lscData_\n- * \\brief The tabular lsc data\n- *\n- * Maps colour temperatures to per-colour channel vector of gains\n- */\n-\n /**\n  * \\class LscTable\n  * \\brief Table based lsc algorithm implementation\n@@ -119,8 +26,13 @@ std::vector<uint16_t> LscTableBase::parseTable(const ValueNode &tuningData,\n \n /**\n  * \\fn LscTable::parseLscData()\n+ * \\brief Parse tabular lsc data\n+ * \\param[in] sets The tuning file content\n+ * \\param[in] descriptor The lsc engine descriptor\n+ *\n+ * Parse the lsc data in tabular form from the \\a sets tuning data.\n  *\n- * \\copydoc LscTableBase::parseLscData()\n+ * \\return 0 on success or a negative error number otherwise\n  */\n \n } /* namespace ipa */\ndiff --git a/src/ipa/libipa/lsc_table.h b/src/ipa/libipa/lsc_table.h\nindex 65e04b09c3ff..fe4e133060a6 100644\n--- a/src/ipa/libipa/lsc_table.h\n+++ b/src/ipa/libipa/lsc_table.h\n@@ -23,34 +23,33 @@ LOG_DECLARE_CATEGORY(LscTable)\n \n namespace ipa {\n \n-class LscTableBase\n+template<typename U>\n+class LscTable : public LscImplementation<U>\n {\n-protected:\n-\tint parseLscData(const ValueNode &sets,\n-\t\t\t const LscDescriptor &descriptor);\n-\n private:\n-\tint parseLscComponent(const ValueNode &yamlSet,\n-\t\t\t      unsigned int ct, const LscDescriptor &descriptor);\n-\tstd::vector<uint16_t> parseTable(const ValueNode &tuningData,\n-\t\t\t\t\t const char *prop,\n-\t\t\t\t\t unsigned int numHCells,\n-\t\t\t\t\t unsigned int numVCells);\n-protected:\n-\tlsc::ComponentsMap lscData_;\n-};\n+\tusing T = typename U::QuantizedType;\n \n-template<typename U>\n-class LscTable : public LscTableBase, public LscImplementation<U>\n-{\n public:\n \tint parseLscData(const ValueNode &sets,\n \t\t\t const LscDescriptor &descriptor) override\n \t{\n-\t\treturn LscTableBase::parseLscData(sets, descriptor);\n+\t\tfor (const auto &set : sets.asList()) {\n+\t\t\tuint32_t ct = set[\"ct\"].get<uint32_t>(0);\n+\n+\t\t\tint ret = parseLscComponent(set, ct, descriptor);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\n+\t\tif (lscData_.empty()) {\n+\t\t\tLOG(LscTable, Error) << \"Failed to load any sets\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\treturn 0;\n \t}\n \n-\tlsc::ComponentsMap\n+\tlsc::ComponentsMap<T>\n \tsampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,\n \t\t      [[maybe_unused]] std::vector<double> xPos,\n \t\t      [[maybe_unused]] std::vector<double> yPos) override\n@@ -59,6 +58,59 @@ public:\n \t\t\t<< \"Tabular LSC data doesn't support resampling\";\n \t\treturn lscData_;\n \t}\n+\n+private:\n+\tint parseLscComponent(const ValueNode &yamlSet,\n+\t\t\t      unsigned int ct, const LscDescriptor &descriptor)\n+\t{\n+\t\tlsc::Components<T> component;\n+\t\tfor (auto &k : descriptor.keys) {\n+\t\t\tauto [it, inserted] = component.emplace(\n+\t\t\t\tstd::piecewise_construct,\n+\t\t\t\tstd::forward_as_tuple(k.c_str()),\n+\t\t\t\tstd::forward_as_tuple(parseTable(yamlSet,\n+\t\t\t\t\t\t\t\t k.c_str(),\n+\t\t\t\t\t\t\t\t descriptor.numHCells,\n+\t\t\t\t\t\t\t\t descriptor.numVCells)));\n+\t\t\tif (!inserted || it->second.empty()) {\n+\t\t\t\tLOG(LscTable, Error)\n+\t\t\t\t\t<< \"Set \" << k << \" for color temperature \"\n+\t\t\t\t\t<< ct << \" is missing\";\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t}\n+\n+\t\tauto [it, inserted] = lscData_.emplace(ct, component);\n+\t\tif (!inserted) {\n+\t\t\tLOG(LscTable, Error)\n+\t\t\t\t<< \"Multiple sets found for color temperature \"\n+\t\t\t\t<< ct;\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\treturn 0;\n+\t}\n+\n+\tstd::vector<T> parseTable(const ValueNode &tuningData,\n+\t\t\t\t  const char *prop, unsigned int numHCells,\n+\t\t\t\t  unsigned int numVCells)\n+\t{\n+\t\tunsigned int kLscNumSamples = numHCells * numVCells;\n+\n+\t\tstd::vector<T> table =\n+\t\t\ttuningData[prop].get<std::vector<T>>().value_or(utils::defopt);\n+\t\tif (table.size() != kLscNumSamples) {\n+\t\t\tLOG(LscTable, Error)\n+\t\t\t\t<< \"Invalid '\" << prop << \"' values: expected \"\n+\t\t\t\t<< kLscNumSamples\n+\t\t\t\t<< \" elements, got \" << table.size();\n+\t\t\treturn {};\n+\t\t}\n+\n+\t\treturn table;\n+\t}\n+\n+\tlsc::ComponentsMap<T> lscData_;\n };\n \n } /* namespace ipa */\ndiff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp\nindex 79d68ac7d6dd..9e3dc517f6cb 100644\n--- a/src/ipa/rkisp1/algorithms/lsc.cpp\n+++ b/src/ipa/rkisp1/algorithms/lsc.cpp\n@@ -176,7 +176,7 @@ void LensShadingCorrection::setParameters(rkisp1_cif_isp_lsc_config &config)\n }\n \n void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,\n-\t\t\t\t      const lsc::Components &set)\n+\t\t\t\t      const lsc::Components<uint16_t> &set)\n {\n \tconst auto &r = set.at(\"r\");\n \tstd::copy(r.begin(), r.end(), &config.r_data_tbl[0][0]);\n@@ -235,7 +235,7 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context,\n \n \tsetParameters(*config);\n \n-\tconst lsc::Components &set = lscAlgo_.interpolateComponents(quantizedCt);\n+\tconst lsc::Components<uint16_t> &set = lscAlgo_.interpolateComponents(quantizedCt);\n \tcopyTable(*config, set);\n \n \tlastAppliedCt_ = ct;\ndiff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h\nindex 31156f56cd21..eb32997d64bc 100644\n--- a/src/ipa/rkisp1/algorithms/lsc.h\n+++ b/src/ipa/rkisp1/algorithms/lsc.h\n@@ -42,7 +42,8 @@ public:\n \t\t     ControlList &metadata) override;\n private:\n \tvoid setParameters(rkisp1_cif_isp_lsc_config &config);\n-\tvoid copyTable(rkisp1_cif_isp_lsc_config &config, const lsc::Components &set0);\n+\tvoid copyTable(rkisp1_cif_isp_lsc_config &config,\n+\t\t       const lsc::Components<uint16_t> &set0);\n \tstd::vector<double> parseSizes(const ValueNode &tuningData,\n \t\t\t\t       const char *prop);\n \tstd::vector<double> sizesListToPositions(Span<const double> sizes);\n",
    "prefixes": [
        "v3",
        "31/35"
    ]
}