[{"id":39655,"web_url":"https://patchwork.libcamera.org/comment/39655/","msgid":"<178360219836.2174993.13721070174944934159@ping.linuxembedded.co.uk>","date":"2026-07-09T13:03:18","subject":"Re: [PATCH v5 10/36] ipa: libipa: Introduce lsc_base.h","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Jacopo Mondi (2026-07-08 16:50:52)\n> Group in an header file part of libipa the definition of the lsc\n\n\"Group in\" sounds odd...\n\nLets read the patch to find out what it means\n\n\nI'd write:\n\n\"\"\"\nProvide a header and implementation for the base definitions of common\nlens shading calibration data types, and move re-usable code out from\nthe RkISP1 lsc algorithm.\n\"\"\"\n\nbut whatever goes:\n\nonly small bits below - \n\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n\n> Components and the LscImplementation interface definition.\n> \n> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> ---\n>  src/ipa/libipa/lsc_base.cpp       | 95 +++++++++++++++++++++++++++++++++++++++\n>  src/ipa/libipa/lsc_base.h         | 53 ++++++++++++++++++++++\n>  src/ipa/libipa/meson.build        |  2 +\n>  src/ipa/rkisp1/algorithms/lsc.cpp | 28 ++++++------\n>  src/ipa/rkisp1/algorithms/lsc.h   | 29 ++----------\n>  5 files changed, 167 insertions(+), 40 deletions(-)\n> \n> diff --git a/src/ipa/libipa/lsc_base.cpp b/src/ipa/libipa/lsc_base.cpp\n> new file mode 100644\n> index 000000000000..d05075b988d7\n> --- /dev/null\n> +++ b/src/ipa/libipa/lsc_base.cpp\n> @@ -0,0 +1,95 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2026 Ideas on Board Oy\n> + *\n> + * Base classes and types for LSC algorithms implementations\n\nnit: /algorithms/algorithm/\n\n> + */\n> +\n> +#include \"lsc_base.h\"\n> +\n> +/**\n> + * \\file lsc_base.h\n> + * \\brief Base types and definitions for LscImplementation class hierarchy\n> + */\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa {\n> +\n> +namespace lsc {\n> +\n> +/**\n> + * \\struct Components\n> + * \\brief Associate a colour components with a list of gains\n\nAssociate colour components with a list of gains\n\n(s/ a / /)\n\nI know it might be stored as a list, but really it's a table right ?\n\nBut it's fine as it is.\n\n> + *\n> + * LSC tables are defined as a list of gain values associated to a colour\n> + * component.\n> + *\n> + * \\var Components::r\n> + * \\brief The list of gains for the Red colour component\n> + *\n> + * \\var Components::gr\n> + * \\brief The list of gains for the Green/Red colour component\n> + *\n> + * \\var Components::gb\n> + * \\brief The list of gains for the Green/Blue colour component\n> + *\n> + * \\var Components::b\n> + * \\brief The list of gains for the Blue colour component\n> + */\n> +\n> +/**\n> + * \\typedef ComponentsMap\n> + * \\brief Associate a colour temperature to a LSC table\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> + * several different colour temperatures.\n> + */\n> +\n> +} /* namespace lsc */\n> +\n> +/**\n> + * \\class LscImplementation\n> + * \\brief Pure virtual base class for LSC algorithm implementations\n> + *\n> + * Defines the interface for the LSC algorithm implementation.\n> + */\n> +\n> +/**\n> + * \\fn LscImplementation::~LscImplementation\n> + * \\brief Virtual class destructor\n> + */\n> +\n> +/**\n> + * \\fn LscImplementation::parseLscData\n> + * \\brief Parse \\a tuningData\n> + * \\param[in] tuningData The tuning data\n> + *\n> + * \\return 0 on success, a negative error number otherwise\n> + */\n> +\n> +/**\n> + * \\fn LscImplementation::sampleForCrop\n> + * \\brief Re-sample the LSC components for \\a cropRectangle\n> + * \\param[in] cropRectangle The sensor analogue crop rectangle\n> + * \\param[in] xSizes List of horizontal positions of the LSC grid nodes\n> + * \\param[in] ySizes List of vertical positions of the LSC grid nodes\n> + *\n> + * LSC tables have to be re-sampled every time a new sensor configuration is\n> + * used, as each streaming session might use a different sensor crop rectangle\n> + * \\a cropRectangle.\n> + *\n> + * \\a cropRectangle represents the size of the frame on which the LSC tables\n> + * have to be re-sampled on.\n> + *\n> + * \\a xSizes and \\a ySizes represent the position of the grid nodes vertexes in\n> + * the [0, 1] interval. In example an equally spaced grid of 16 nodes will have\n\ns/In example/For example/\n\n> + * each segment of size 0.0625 and the list of nodes position will be\n> + * [0, 0.0625, 0.125, 0.1875, ... , 1]. It is expected that the first position\n> + * is 0 and the last position is 1.\n> + */\n> +\n> +} /* namespace ipa */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/ipa/libipa/lsc_base.h b/src/ipa/libipa/lsc_base.h\n> new file mode 100644\n> index 000000000000..93f819d3c2af\n> --- /dev/null\n> +++ b/src/ipa/libipa/lsc_base.h\n> @@ -0,0 +1,53 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2026 Ideas on Board Oy\n> + *\n> + * Base classes and types for LSC algorithms implementations\n> + */\n> +\n> +#pragma once\n> +\n> +#include <map>\n> +#include <stdint.h>\n> +#include <string>\n> +#include <vector>\n> +\n> +#include <libcamera/base/span.h>\n> +\n> +#include <libcamera/geometry.h>\n> +\n> +#include \"libcamera/internal/value_node.h\"\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa {\n> +\n> +namespace lsc {\n> +\n> +struct Components {\n> +       std::vector<uint16_t> r;\n> +       std::vector<uint16_t> gr;\n> +       std::vector<uint16_t> gb;\n> +       std::vector<uint16_t> b;\n> +};\n> +\n> +using ComponentsMap = std::map<unsigned int, Components>;\n> +\n> +} /* namespace lsc */\n> +\n> +class LscImplementation\n> +{\n> +public:\n> +       virtual ~LscImplementation() {}\n> +\n> +       virtual int parseLscData(const ValueNode &tuningData) = 0;\n> +\n> +       virtual lsc::ComponentsMap\n> +       sampleForCrop(const Rectangle &cropRectangle,\n> +                     Span<const double> xSizes,\n> +                     Span<const double> ySizes) = 0;\n> +};\n> +\n> +} /* namespace ipa */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build\n> index edf8eabd8b78..96611e90ee1e 100644\n> --- a/src/ipa/libipa/meson.build\n> +++ b/src/ipa/libipa/meson.build\n> @@ -14,6 +14,7 @@ libipa_headers = files([\n>      'fixedpoint.h',\n>      'histogram.h',\n>      'interpolator.h',\n> +    'lsc_base.h',\n>      'lsc_polynomial.h',\n>      'lux.h',\n>      'module.h',\n> @@ -36,6 +37,7 @@ libipa_sources = files([\n>      'fixedpoint.cpp',\n>      'histogram.cpp',\n>      'interpolator.cpp',\n> +    'lsc_base.cpp',\n>      'lsc_polynomial.cpp',\n>      'lux.cpp',\n>      'module.cpp',\n> diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp\n> index 38380aa839c6..af919f7429af 100644\n> --- a/src/ipa/rkisp1/algorithms/lsc.cpp\n> +++ b/src/ipa/rkisp1/algorithms/lsc.cpp\n> @@ -38,10 +38,10 @@ void interpolateVector(const std::vector<T> &a, const std::vector<T> &b,\n>  }\n>  \n>  template<>\n> -void Interpolator<rkisp1::algorithms::LensShadingCorrection::Components>::\n> -       interpolate(const rkisp1::algorithms::LensShadingCorrection::Components &a,\n> -                   const rkisp1::algorithms::LensShadingCorrection::Components &b,\n> -                   rkisp1::algorithms::LensShadingCorrection::Components &dest,\n> +void Interpolator<lsc::Components>::\n> +       interpolate(const lsc::Components &a,\n> +                   const lsc::Components &b,\n> +                   lsc::Components &dest,\n>                     double lambda)\n>  {\n>         interpolateVector(a.r, b.r, dest.r, lambda);\n> @@ -80,7 +80,7 @@ public:\n>  \n>         int parseLscData(const ValueNode &sets) override;\n>  \n> -       LensShadingCorrection::ComponentsMap\n> +       lsc::ComponentsMap\n>         sampleForCrop(const Rectangle &cropRectangle,\n>                       Span<const double> xSizes,\n>                       Span<const double> ySizes) override;\n> @@ -138,7 +138,7 @@ int LscPolynomialImpl::parseLscData(const ValueNode &sets)\n>         return 0;\n>  }\n>  \n> -LensShadingCorrection::ComponentsMap\n> +lsc::ComponentsMap\n>  LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle,\n>                                  Span<const double> xSizes,\n>                                  Span<const double> ySizes)\n> @@ -146,7 +146,7 @@ LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle,\n>         std::vector<double> xPos = sizesListToPositions(xSizes);\n>         std::vector<double> yPos = sizesListToPositions(ySizes);\n>  \n> -       LensShadingCorrection::ComponentsMap components;\n> +       lsc::ComponentsMap components;\n>  \n>         for (const auto &[k, p] : lscData_) {\n>                 components[k] = {\n> @@ -226,7 +226,7 @@ class LscTableImpl : public LscImplementation\n>  public:\n>         int parseLscData(const ValueNode &sets) override;\n>  \n> -       LensShadingCorrection::ComponentsMap\n> +       lsc::ComponentsMap\n>         sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,\n>                       [[maybe_unused]] Span<const double> xSizes,\n>                       [[maybe_unused]] Span<const double> ySizes) override\n> @@ -240,7 +240,7 @@ private:\n>         std::vector<uint16_t> parseTable(const ValueNode &tuningData,\n>                                          const char *prop);\n>  \n> -       LensShadingCorrection::ComponentsMap lscData_;\n> +       lsc::ComponentsMap lscData_;\n>  };\n>  \n>  int LscTableImpl::parseLscData(const ValueNode &sets)\n> @@ -255,7 +255,7 @@ int LscTableImpl::parseLscData(const ValueNode &sets)\n>                         return -EINVAL;\n>                 }\n>  \n> -               LensShadingCorrection::Components components;\n> +               lsc::Components components;\n>                 components.r = parseTable(set, \"r\");\n>                 components.gr = parseTable(set, \"gr\");\n>                 components.gb = parseTable(set, \"gb\");\n> @@ -435,8 +435,8 @@ int LensShadingCorrection::configure(IPAContext &context,\n>         }\n>  \n>         LOG(RkISP1Lsc, Debug) << \"Sample LSC data for \" << configInfo.analogCrop;\n> -       ComponentsMap shadingData = algo_->sampleForCrop(configInfo.analogCrop,\n> -                                                        xSize_, ySize_);\n> +       lsc::ComponentsMap shadingData = algo_->sampleForCrop(configInfo.analogCrop,\n> +                                                             xSize_, ySize_);\n>         sets_.setData(std::move(shadingData));\n>  \n>         context.activeState.lsc.enabled = true;\n> @@ -452,7 +452,7 @@ void LensShadingCorrection::setParameters(rkisp1_cif_isp_lsc_config &config)\n>  }\n>  \n>  void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,\n> -                                     const Components &set)\n> +                                     const lsc::Components &set)\n>  {\n>         std::copy(set.r.begin(), set.r.end(), &config.r_data_tbl[0][0]);\n>         std::copy(set.gr.begin(), set.gr.end(), &config.gr_data_tbl[0][0]);\n> @@ -518,7 +518,7 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context,\n>  \n>         setParameters(*config);\n>  \n> -       const Components &set = sets_.getInterpolated(quantizedCt);\n> +       const lsc::Components &set = sets_.getInterpolated(quantizedCt);\n>         copyTable(*config, set);\n>  \n>         lastAppliedCt_ = ct;\n> diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h\n> index 3463531f2ab2..b21c91c0d81f 100644\n> --- a/src/ipa/rkisp1/algorithms/lsc.h\n> +++ b/src/ipa/rkisp1/algorithms/lsc.h\n> @@ -11,6 +11,7 @@\n>  #include <memory>\n>  \n>  #include \"libipa/interpolator.h\"\n> +#include \"libipa/lsc_base.h\"\n>  \n>  #include \"algorithm.h\"\n>  \n> @@ -18,20 +19,9 @@ namespace libcamera {\n>  \n>  namespace ipa::rkisp1::algorithms {\n>  \n> -class LscImplementation;\n> -\n>  class LensShadingCorrection : public Algorithm\n>  {\n>  public:\n> -       struct Components {\n> -               std::vector<uint16_t> r;\n> -               std::vector<uint16_t> gr;\n> -               std::vector<uint16_t> gb;\n> -               std::vector<uint16_t> b;\n> -       };\n> -\n> -       using ComponentsMap = std::map<unsigned int, Components>;\n> -\n>         LensShadingCorrection();\n>         ~LensShadingCorrection() = default;\n>  \n> @@ -49,7 +39,7 @@ public:\n>                      ControlList &metadata) override;\n>  private:\n>         void setParameters(rkisp1_cif_isp_lsc_config &config);\n> -       void copyTable(rkisp1_cif_isp_lsc_config &config, const Components &set0);\n> +       void copyTable(rkisp1_cif_isp_lsc_config &config, const lsc::Components &set0);\n>  \n>         std::vector<double> xSize_;\n>         std::vector<double> ySize_;\n> @@ -61,23 +51,10 @@ private:\n>         unsigned int lastAppliedCt_;\n>         unsigned int lastAppliedQuantizedCt_;\n>  \n> -       ipa::Interpolator<Components> sets_;\n> +       ipa::Interpolator<lsc::Components> sets_;\n>  \n>         std::unique_ptr<LscImplementation> algo_;\n>  };\n>  \n> -class LscImplementation\n> -{\n> -public:\n> -       virtual ~LscImplementation() {}\n> -\n> -       virtual int parseLscData(const ValueNode &sets) = 0;\n> -\n> -       virtual LensShadingCorrection::ComponentsMap\n> -       sampleForCrop(const Rectangle &cropRectangle,\n> -                     Span<const double> xSizes,\n> -                     Span<const double> ySizes) = 0;\n> -};\n> -\n>  } /* namespace ipa::rkisp1::algorithms */\n>  } /* namespace libcamera */\n> \n> -- \n> 2.54.0\n>","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 9D15EBF415\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  9 Jul 2026 13:03:23 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 8B35A660EC;\n\tThu,  9 Jul 2026 15:03:22 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 44658660E3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  9 Jul 2026 15:03:21 +0200 (CEST)","from monstersaurus.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 8A5544DC;\n\tThu,  9 Jul 2026 15:02:30 +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=\"ahBexhru\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1783602150;\n\tbh=7BDeLh1JY4d48n3vnGtQs5o82ngofaKR7WUloRgDHe0=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=ahBexhru/0YsRIGEiUFIh5g1LrXWCdvr+CE2WxLpXOtf8Ym6134ZbucXL0yz7HVlQ\n\tPb3js35zG2GoRy2Nb5IoJsWch2MEhD4888XIJ30pcEDHAIBln/qxezsaTsTI6iLZzj\n\tqy+4HeAv5AoBwWuJsd3ss1wFYelEuBHKE4O5LFC8=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20260708-libipa-algorithms-v5-10-0759d0359f52@ideasonboard.com>","References":"<20260708-libipa-algorithms-v5-0-0759d0359f52@ideasonboard.com>\n\t<20260708-libipa-algorithms-v5-10-0759d0359f52@ideasonboard.com>","Subject":"Re: [PATCH v5 10/36] ipa: libipa: Introduce lsc_base.h","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tStefan Klug <stefan.klug@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Thu, 09 Jul 2026 14:03:18 +0100","Message-ID":"<178360219836.2174993.13721070174944934159@ping.linuxembedded.co.uk>","User-Agent":"alot/0.9.1","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>"}},{"id":39674,"web_url":"https://patchwork.libcamera.org/comment/39674/","msgid":"<178394864048.3603632.15526588471661533636@localhost>","date":"2026-07-13T13:17:20","subject":"Re: [PATCH v5 10/36] ipa: libipa: Introduce lsc_base.h","submitter":{"id":184,"url":"https://patchwork.libcamera.org/api/people/184/","name":"Stefan Klug","email":"stefan.klug@ideasonboard.com"},"content":"Hi Jacopo,\n\nQuoting Jacopo Mondi (2026-07-08 17:50:52)\n> Group in an header file part of libipa the definition of the lsc\n> Components and the LscImplementation interface definition.\n> \n> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> ---\n>  src/ipa/libipa/lsc_base.cpp       | 95 +++++++++++++++++++++++++++++++++++++++\n>  src/ipa/libipa/lsc_base.h         | 53 ++++++++++++++++++++++\n>  src/ipa/libipa/meson.build        |  2 +\n>  src/ipa/rkisp1/algorithms/lsc.cpp | 28 ++++++------\n>  src/ipa/rkisp1/algorithms/lsc.h   | 29 ++----------\n>  5 files changed, 167 insertions(+), 40 deletions(-)\n> \n> diff --git a/src/ipa/libipa/lsc_base.cpp b/src/ipa/libipa/lsc_base.cpp\n> new file mode 100644\n> index 000000000000..d05075b988d7\n> --- /dev/null\n> +++ b/src/ipa/libipa/lsc_base.cpp\n> @@ -0,0 +1,95 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2026 Ideas on Board Oy\n> + *\n> + * Base classes and types for LSC algorithms implementations\n> + */\n> +\n> +#include \"lsc_base.h\"\n> +\n> +/**\n> + * \\file lsc_base.h\n> + * \\brief Base types and definitions for LscImplementation class hierarchy\n> + */\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa {\n> +\n> +namespace lsc {\n> +\n> +/**\n> + * \\struct Components\n> + * \\brief Associate a colour components with a list of gains\n> + *\n> + * LSC tables are defined as a list of gain values associated to a colour\n> + * component.\n> + *\n> + * \\var Components::r\n> + * \\brief The list of gains for the Red colour component\n> + *\n> + * \\var Components::gr\n> + * \\brief The list of gains for the Green/Red colour component\n> + *\n> + * \\var Components::gb\n> + * \\brief The list of gains for the Green/Blue colour component\n> + *\n> + * \\var Components::b\n> + * \\brief The list of gains for the Blue colour component\n> + */\n> +\n> +/**\n> + * \\typedef ComponentsMap\n> + * \\brief Associate a colour temperature to a LSC table\n> + *\n> + * An LSC table is generated during the tuning phase for a specific light\n\nnit: We use colour temperature everywhere.\n\nI read the comments from Kieran and have aside from tha, nothing to add.\n\nReviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>\n\nBest regards,\nStefan\n\n> + * temperature, and a tuning file usually contains LSC tables generated for\n> + * several different colour temperatures.\n> + */\n> +\n> +} /* namespace lsc */\n> +\n> +/**\n> + * \\class LscImplementation\n> + * \\brief Pure virtual base class for LSC algorithm implementations\n> + *\n> + * Defines the interface for the LSC algorithm implementation.\n> + */\n> +\n> +/**\n> + * \\fn LscImplementation::~LscImplementation\n> + * \\brief Virtual class destructor\n> + */\n> +\n> +/**\n> + * \\fn LscImplementation::parseLscData\n> + * \\brief Parse \\a tuningData\n> + * \\param[in] tuningData The tuning data\n> + *\n> + * \\return 0 on success, a negative error number otherwise\n> + */\n> +\n> +/**\n> + * \\fn LscImplementation::sampleForCrop\n> + * \\brief Re-sample the LSC components for \\a cropRectangle\n> + * \\param[in] cropRectangle The sensor analogue crop rectangle\n> + * \\param[in] xSizes List of horizontal positions of the LSC grid nodes\n> + * \\param[in] ySizes List of vertical positions of the LSC grid nodes\n> + *\n> + * LSC tables have to be re-sampled every time a new sensor configuration is\n> + * used, as each streaming session might use a different sensor crop rectangle\n> + * \\a cropRectangle.\n> + *\n> + * \\a cropRectangle represents the size of the frame on which the LSC tables\n> + * have to be re-sampled on.\n> + *\n> + * \\a xSizes and \\a ySizes represent the position of the grid nodes vertexes in\n> + * the [0, 1] interval. In example an equally spaced grid of 16 nodes will have\n> + * each segment of size 0.0625 and the list of nodes position will be\n> + * [0, 0.0625, 0.125, 0.1875, ... , 1]. It is expected that the first position\n> + * is 0 and the last position is 1.\n> + */\n> +\n> +} /* namespace ipa */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/ipa/libipa/lsc_base.h b/src/ipa/libipa/lsc_base.h\n> new file mode 100644\n> index 000000000000..93f819d3c2af\n> --- /dev/null\n> +++ b/src/ipa/libipa/lsc_base.h\n> @@ -0,0 +1,53 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2026 Ideas on Board Oy\n> + *\n> + * Base classes and types for LSC algorithms implementations\n> + */\n> +\n> +#pragma once\n> +\n> +#include <map>\n> +#include <stdint.h>\n> +#include <string>\n> +#include <vector>\n> +\n> +#include <libcamera/base/span.h>\n> +\n> +#include <libcamera/geometry.h>\n> +\n> +#include \"libcamera/internal/value_node.h\"\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa {\n> +\n> +namespace lsc {\n> +\n> +struct Components {\n> +       std::vector<uint16_t> r;\n> +       std::vector<uint16_t> gr;\n> +       std::vector<uint16_t> gb;\n> +       std::vector<uint16_t> b;\n> +};\n> +\n> +using ComponentsMap = std::map<unsigned int, Components>;\n> +\n> +} /* namespace lsc */\n> +\n> +class LscImplementation\n> +{\n> +public:\n> +       virtual ~LscImplementation() {}\n> +\n> +       virtual int parseLscData(const ValueNode &tuningData) = 0;\n> +\n> +       virtual lsc::ComponentsMap\n> +       sampleForCrop(const Rectangle &cropRectangle,\n> +                     Span<const double> xSizes,\n> +                     Span<const double> ySizes) = 0;\n> +};\n> +\n> +} /* namespace ipa */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build\n> index edf8eabd8b78..96611e90ee1e 100644\n> --- a/src/ipa/libipa/meson.build\n> +++ b/src/ipa/libipa/meson.build\n> @@ -14,6 +14,7 @@ libipa_headers = files([\n>      'fixedpoint.h',\n>      'histogram.h',\n>      'interpolator.h',\n> +    'lsc_base.h',\n>      'lsc_polynomial.h',\n>      'lux.h',\n>      'module.h',\n> @@ -36,6 +37,7 @@ libipa_sources = files([\n>      'fixedpoint.cpp',\n>      'histogram.cpp',\n>      'interpolator.cpp',\n> +    'lsc_base.cpp',\n>      'lsc_polynomial.cpp',\n>      'lux.cpp',\n>      'module.cpp',\n> diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp\n> index 38380aa839c6..af919f7429af 100644\n> --- a/src/ipa/rkisp1/algorithms/lsc.cpp\n> +++ b/src/ipa/rkisp1/algorithms/lsc.cpp\n> @@ -38,10 +38,10 @@ void interpolateVector(const std::vector<T> &a, const std::vector<T> &b,\n>  }\n>  \n>  template<>\n> -void Interpolator<rkisp1::algorithms::LensShadingCorrection::Components>::\n> -       interpolate(const rkisp1::algorithms::LensShadingCorrection::Components &a,\n> -                   const rkisp1::algorithms::LensShadingCorrection::Components &b,\n> -                   rkisp1::algorithms::LensShadingCorrection::Components &dest,\n> +void Interpolator<lsc::Components>::\n> +       interpolate(const lsc::Components &a,\n> +                   const lsc::Components &b,\n> +                   lsc::Components &dest,\n>                     double lambda)\n>  {\n>         interpolateVector(a.r, b.r, dest.r, lambda);\n> @@ -80,7 +80,7 @@ public:\n>  \n>         int parseLscData(const ValueNode &sets) override;\n>  \n> -       LensShadingCorrection::ComponentsMap\n> +       lsc::ComponentsMap\n>         sampleForCrop(const Rectangle &cropRectangle,\n>                       Span<const double> xSizes,\n>                       Span<const double> ySizes) override;\n> @@ -138,7 +138,7 @@ int LscPolynomialImpl::parseLscData(const ValueNode &sets)\n>         return 0;\n>  }\n>  \n> -LensShadingCorrection::ComponentsMap\n> +lsc::ComponentsMap\n>  LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle,\n>                                  Span<const double> xSizes,\n>                                  Span<const double> ySizes)\n> @@ -146,7 +146,7 @@ LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle,\n>         std::vector<double> xPos = sizesListToPositions(xSizes);\n>         std::vector<double> yPos = sizesListToPositions(ySizes);\n>  \n> -       LensShadingCorrection::ComponentsMap components;\n> +       lsc::ComponentsMap components;\n>  \n>         for (const auto &[k, p] : lscData_) {\n>                 components[k] = {\n> @@ -226,7 +226,7 @@ class LscTableImpl : public LscImplementation\n>  public:\n>         int parseLscData(const ValueNode &sets) override;\n>  \n> -       LensShadingCorrection::ComponentsMap\n> +       lsc::ComponentsMap\n>         sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,\n>                       [[maybe_unused]] Span<const double> xSizes,\n>                       [[maybe_unused]] Span<const double> ySizes) override\n> @@ -240,7 +240,7 @@ private:\n>         std::vector<uint16_t> parseTable(const ValueNode &tuningData,\n>                                          const char *prop);\n>  \n> -       LensShadingCorrection::ComponentsMap lscData_;\n> +       lsc::ComponentsMap lscData_;\n>  };\n>  \n>  int LscTableImpl::parseLscData(const ValueNode &sets)\n> @@ -255,7 +255,7 @@ int LscTableImpl::parseLscData(const ValueNode &sets)\n>                         return -EINVAL;\n>                 }\n>  \n> -               LensShadingCorrection::Components components;\n> +               lsc::Components components;\n>                 components.r = parseTable(set, \"r\");\n>                 components.gr = parseTable(set, \"gr\");\n>                 components.gb = parseTable(set, \"gb\");\n> @@ -435,8 +435,8 @@ int LensShadingCorrection::configure(IPAContext &context,\n>         }\n>  \n>         LOG(RkISP1Lsc, Debug) << \"Sample LSC data for \" << configInfo.analogCrop;\n> -       ComponentsMap shadingData = algo_->sampleForCrop(configInfo.analogCrop,\n> -                                                        xSize_, ySize_);\n> +       lsc::ComponentsMap shadingData = algo_->sampleForCrop(configInfo.analogCrop,\n> +                                                             xSize_, ySize_);\n>         sets_.setData(std::move(shadingData));\n>  \n>         context.activeState.lsc.enabled = true;\n> @@ -452,7 +452,7 @@ void LensShadingCorrection::setParameters(rkisp1_cif_isp_lsc_config &config)\n>  }\n>  \n>  void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,\n> -                                     const Components &set)\n> +                                     const lsc::Components &set)\n>  {\n>         std::copy(set.r.begin(), set.r.end(), &config.r_data_tbl[0][0]);\n>         std::copy(set.gr.begin(), set.gr.end(), &config.gr_data_tbl[0][0]);\n> @@ -518,7 +518,7 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context,\n>  \n>         setParameters(*config);\n>  \n> -       const Components &set = sets_.getInterpolated(quantizedCt);\n> +       const lsc::Components &set = sets_.getInterpolated(quantizedCt);\n>         copyTable(*config, set);\n>  \n>         lastAppliedCt_ = ct;\n> diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h\n> index 3463531f2ab2..b21c91c0d81f 100644\n> --- a/src/ipa/rkisp1/algorithms/lsc.h\n> +++ b/src/ipa/rkisp1/algorithms/lsc.h\n> @@ -11,6 +11,7 @@\n>  #include <memory>\n>  \n>  #include \"libipa/interpolator.h\"\n> +#include \"libipa/lsc_base.h\"\n>  \n>  #include \"algorithm.h\"\n>  \n> @@ -18,20 +19,9 @@ namespace libcamera {\n>  \n>  namespace ipa::rkisp1::algorithms {\n>  \n> -class LscImplementation;\n> -\n>  class LensShadingCorrection : public Algorithm\n>  {\n>  public:\n> -       struct Components {\n> -               std::vector<uint16_t> r;\n> -               std::vector<uint16_t> gr;\n> -               std::vector<uint16_t> gb;\n> -               std::vector<uint16_t> b;\n> -       };\n> -\n> -       using ComponentsMap = std::map<unsigned int, Components>;\n> -\n>         LensShadingCorrection();\n>         ~LensShadingCorrection() = default;\n>  \n> @@ -49,7 +39,7 @@ public:\n>                      ControlList &metadata) override;\n>  private:\n>         void setParameters(rkisp1_cif_isp_lsc_config &config);\n> -       void copyTable(rkisp1_cif_isp_lsc_config &config, const Components &set0);\n> +       void copyTable(rkisp1_cif_isp_lsc_config &config, const lsc::Components &set0);\n>  \n>         std::vector<double> xSize_;\n>         std::vector<double> ySize_;\n> @@ -61,23 +51,10 @@ private:\n>         unsigned int lastAppliedCt_;\n>         unsigned int lastAppliedQuantizedCt_;\n>  \n> -       ipa::Interpolator<Components> sets_;\n> +       ipa::Interpolator<lsc::Components> sets_;\n>  \n>         std::unique_ptr<LscImplementation> algo_;\n>  };\n>  \n> -class LscImplementation\n> -{\n> -public:\n> -       virtual ~LscImplementation() {}\n> -\n> -       virtual int parseLscData(const ValueNode &sets) = 0;\n> -\n> -       virtual LensShadingCorrection::ComponentsMap\n> -       sampleForCrop(const Rectangle &cropRectangle,\n> -                     Span<const double> xSizes,\n> -                     Span<const double> ySizes) = 0;\n> -};\n> -\n>  } /* namespace ipa::rkisp1::algorithms */\n>  } /* namespace libcamera */\n> \n> -- \n> 2.54.0\n>","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 B4EC1C32CE\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 13 Jul 2026 13:17:26 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C171666111;\n\tMon, 13 Jul 2026 15:17:25 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 755056604D\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 13 Jul 2026 15:17:23 +0200 (CEST)","from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:6c1f:355d:1c19:aba6])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id CFFA719FC;\n\tMon, 13 Jul 2026 15:16: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=\"XZZy3oQi\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1783948589;\n\tbh=njMVeiJRV9ePR7h/0a6Zmu5qujoCgUEycJCU9f3Kh0s=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=XZZy3oQiJcpPdDHAoYuZxlyoDmpEGZ1m0KubuM1BvEt+t2OMAOqihLYlMn0P7nI1R\n\t/aesAxR5vBJVreb2NHEiDkKxiw+pIXeUfV72NNF8Y5CAzAmeybCN1z4/MGCUbaWITA\n\tIdJ1hl2tG/mbSQb8wOfgosD6PhOxFMmdVPluLHq0=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20260708-libipa-algorithms-v5-10-0759d0359f52@ideasonboard.com>","References":"<20260708-libipa-algorithms-v5-0-0759d0359f52@ideasonboard.com>\n\t<20260708-libipa-algorithms-v5-10-0759d0359f52@ideasonboard.com>","Subject":"Re: [PATCH v5 10/36] ipa: libipa: Introduce lsc_base.h","From":"Stefan Klug <stefan.klug@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Mon, 13 Jul 2026 15:17:20 +0200","Message-ID":"<178394864048.3603632.15526588471661533636@localhost>","User-Agent":"alot/0.12.dev43+g2cacc0d03","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>"}}]