[v5,10/36] ipa: libipa: Introduce lsc_base.h
diff mbox series

Message ID 20260708-libipa-algorithms-v5-10-0759d0359f52@ideasonboard.com
State Superseded
Headers show
Series
  • ipa: libipa: Introduce libipa algorithms
Related show

Commit Message

Jacopo Mondi July 8, 2026, 3:50 p.m. UTC
Group in an header file part of libipa the definition of the lsc
Components and the LscImplementation interface definition.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 src/ipa/libipa/lsc_base.cpp       | 95 +++++++++++++++++++++++++++++++++++++++
 src/ipa/libipa/lsc_base.h         | 53 ++++++++++++++++++++++
 src/ipa/libipa/meson.build        |  2 +
 src/ipa/rkisp1/algorithms/lsc.cpp | 28 ++++++------
 src/ipa/rkisp1/algorithms/lsc.h   | 29 ++----------
 5 files changed, 167 insertions(+), 40 deletions(-)

Comments

Kieran Bingham July 9, 2026, 1:03 p.m. UTC | #1
Quoting Jacopo Mondi (2026-07-08 16:50:52)
> Group in an header file part of libipa the definition of the lsc

"Group in" sounds odd...

Lets read the patch to find out what it means


I'd write:

"""
Provide a header and implementation for the base definitions of common
lens shading calibration data types, and move re-usable code out from
the RkISP1 lsc algorithm.
"""

but whatever goes:

only small bits below - 


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>


> Components and the LscImplementation interface definition.
> 
> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> ---
>  src/ipa/libipa/lsc_base.cpp       | 95 +++++++++++++++++++++++++++++++++++++++
>  src/ipa/libipa/lsc_base.h         | 53 ++++++++++++++++++++++
>  src/ipa/libipa/meson.build        |  2 +
>  src/ipa/rkisp1/algorithms/lsc.cpp | 28 ++++++------
>  src/ipa/rkisp1/algorithms/lsc.h   | 29 ++----------
>  5 files changed, 167 insertions(+), 40 deletions(-)
> 
> diff --git a/src/ipa/libipa/lsc_base.cpp b/src/ipa/libipa/lsc_base.cpp
> new file mode 100644
> index 000000000000..d05075b988d7
> --- /dev/null
> +++ b/src/ipa/libipa/lsc_base.cpp
> @@ -0,0 +1,95 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2026 Ideas on Board Oy
> + *
> + * Base classes and types for LSC algorithms implementations

nit: /algorithms/algorithm/

> + */
> +
> +#include "lsc_base.h"
> +
> +/**
> + * \file lsc_base.h
> + * \brief Base types and definitions for LscImplementation class hierarchy
> + */
> +
> +namespace libcamera {
> +
> +namespace ipa {
> +
> +namespace lsc {
> +
> +/**
> + * \struct Components
> + * \brief Associate a colour components with a list of gains

Associate colour components with a list of gains

(s/ a / /)

I know it might be stored as a list, but really it's a table right ?

But it's fine as it is.

> + *
> + * LSC tables are defined as a list of gain values associated to a colour
> + * component.
> + *
> + * \var Components::r
> + * \brief The list of gains for the Red colour component
> + *
> + * \var Components::gr
> + * \brief The list of gains for the Green/Red colour component
> + *
> + * \var Components::gb
> + * \brief The list of gains for the Green/Blue colour component
> + *
> + * \var Components::b
> + * \brief The list of gains for the Blue colour component
> + */
> +
> +/**
> + * \typedef ComponentsMap
> + * \brief Associate a colour temperature to a LSC table
> + *
> + * An LSC table is generated during the tuning phase for a specific light
> + * temperature, and a tuning file usually contains LSC tables generated for
> + * several different colour temperatures.
> + */
> +
> +} /* namespace lsc */
> +
> +/**
> + * \class LscImplementation
> + * \brief Pure virtual base class for LSC algorithm implementations
> + *
> + * Defines the interface for the LSC algorithm implementation.
> + */
> +
> +/**
> + * \fn LscImplementation::~LscImplementation
> + * \brief Virtual class destructor
> + */
> +
> +/**
> + * \fn LscImplementation::parseLscData
> + * \brief Parse \a tuningData
> + * \param[in] tuningData The tuning data
> + *
> + * \return 0 on success, a negative error number otherwise
> + */
> +
> +/**
> + * \fn LscImplementation::sampleForCrop
> + * \brief Re-sample the LSC components for \a cropRectangle
> + * \param[in] cropRectangle The sensor analogue crop rectangle
> + * \param[in] xSizes List of horizontal positions of the LSC grid nodes
> + * \param[in] ySizes List of vertical positions of the LSC grid nodes
> + *
> + * LSC tables have to be re-sampled every time a new sensor configuration is
> + * used, as each streaming session might use a different sensor crop rectangle
> + * \a cropRectangle.
> + *
> + * \a cropRectangle represents the size of the frame on which the LSC tables
> + * have to be re-sampled on.
> + *
> + * \a xSizes and \a ySizes represent the position of the grid nodes vertexes in
> + * the [0, 1] interval. In example an equally spaced grid of 16 nodes will have

s/In example/For example/

> + * each segment of size 0.0625 and the list of nodes position will be
> + * [0, 0.0625, 0.125, 0.1875, ... , 1]. It is expected that the first position
> + * is 0 and the last position is 1.
> + */
> +
> +} /* namespace ipa */
> +
> +} /* namespace libcamera */
> diff --git a/src/ipa/libipa/lsc_base.h b/src/ipa/libipa/lsc_base.h
> new file mode 100644
> index 000000000000..93f819d3c2af
> --- /dev/null
> +++ b/src/ipa/libipa/lsc_base.h
> @@ -0,0 +1,53 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2026 Ideas on Board Oy
> + *
> + * Base classes and types for LSC algorithms implementations
> + */
> +
> +#pragma once
> +
> +#include <map>
> +#include <stdint.h>
> +#include <string>
> +#include <vector>
> +
> +#include <libcamera/base/span.h>
> +
> +#include <libcamera/geometry.h>
> +
> +#include "libcamera/internal/value_node.h"
> +
> +namespace libcamera {
> +
> +namespace ipa {
> +
> +namespace lsc {
> +
> +struct Components {
> +       std::vector<uint16_t> r;
> +       std::vector<uint16_t> gr;
> +       std::vector<uint16_t> gb;
> +       std::vector<uint16_t> b;
> +};
> +
> +using ComponentsMap = std::map<unsigned int, Components>;
> +
> +} /* namespace lsc */
> +
> +class LscImplementation
> +{
> +public:
> +       virtual ~LscImplementation() {}
> +
> +       virtual int parseLscData(const ValueNode &tuningData) = 0;
> +
> +       virtual lsc::ComponentsMap
> +       sampleForCrop(const Rectangle &cropRectangle,
> +                     Span<const double> xSizes,
> +                     Span<const double> ySizes) = 0;
> +};
> +
> +} /* namespace ipa */
> +
> +} /* namespace libcamera */
> diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
> index edf8eabd8b78..96611e90ee1e 100644
> --- a/src/ipa/libipa/meson.build
> +++ b/src/ipa/libipa/meson.build
> @@ -14,6 +14,7 @@ libipa_headers = files([
>      'fixedpoint.h',
>      'histogram.h',
>      'interpolator.h',
> +    'lsc_base.h',
>      'lsc_polynomial.h',
>      'lux.h',
>      'module.h',
> @@ -36,6 +37,7 @@ libipa_sources = files([
>      'fixedpoint.cpp',
>      'histogram.cpp',
>      'interpolator.cpp',
> +    'lsc_base.cpp',
>      'lsc_polynomial.cpp',
>      'lux.cpp',
>      'module.cpp',
> diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp
> index 38380aa839c6..af919f7429af 100644
> --- a/src/ipa/rkisp1/algorithms/lsc.cpp
> +++ b/src/ipa/rkisp1/algorithms/lsc.cpp
> @@ -38,10 +38,10 @@ void interpolateVector(const std::vector<T> &a, const std::vector<T> &b,
>  }
>  
>  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,
> +void Interpolator<lsc::Components>::
> +       interpolate(const lsc::Components &a,
> +                   const lsc::Components &b,
> +                   lsc::Components &dest,
>                     double lambda)
>  {
>         interpolateVector(a.r, b.r, dest.r, lambda);
> @@ -80,7 +80,7 @@ public:
>  
>         int parseLscData(const ValueNode &sets) override;
>  
> -       LensShadingCorrection::ComponentsMap
> +       lsc::ComponentsMap
>         sampleForCrop(const Rectangle &cropRectangle,
>                       Span<const double> xSizes,
>                       Span<const double> ySizes) override;
> @@ -138,7 +138,7 @@ int LscPolynomialImpl::parseLscData(const ValueNode &sets)
>         return 0;
>  }
>  
> -LensShadingCorrection::ComponentsMap
> +lsc::ComponentsMap
>  LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle,
>                                  Span<const double> xSizes,
>                                  Span<const double> ySizes)
> @@ -146,7 +146,7 @@ LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle,
>         std::vector<double> xPos = sizesListToPositions(xSizes);
>         std::vector<double> yPos = sizesListToPositions(ySizes);
>  
> -       LensShadingCorrection::ComponentsMap components;
> +       lsc::ComponentsMap components;
>  
>         for (const auto &[k, p] : lscData_) {
>                 components[k] = {
> @@ -226,7 +226,7 @@ class LscTableImpl : public LscImplementation
>  public:
>         int parseLscData(const ValueNode &sets) override;
>  
> -       LensShadingCorrection::ComponentsMap
> +       lsc::ComponentsMap
>         sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,
>                       [[maybe_unused]] Span<const double> xSizes,
>                       [[maybe_unused]] Span<const double> ySizes) override
> @@ -240,7 +240,7 @@ private:
>         std::vector<uint16_t> parseTable(const ValueNode &tuningData,
>                                          const char *prop);
>  
> -       LensShadingCorrection::ComponentsMap lscData_;
> +       lsc::ComponentsMap lscData_;
>  };
>  
>  int LscTableImpl::parseLscData(const ValueNode &sets)
> @@ -255,7 +255,7 @@ int LscTableImpl::parseLscData(const ValueNode &sets)
>                         return -EINVAL;
>                 }
>  
> -               LensShadingCorrection::Components components;
> +               lsc::Components components;
>                 components.r = parseTable(set, "r");
>                 components.gr = parseTable(set, "gr");
>                 components.gb = parseTable(set, "gb");
> @@ -435,8 +435,8 @@ int LensShadingCorrection::configure(IPAContext &context,
>         }
>  
>         LOG(RkISP1Lsc, Debug) << "Sample LSC data for " << configInfo.analogCrop;
> -       ComponentsMap shadingData = algo_->sampleForCrop(configInfo.analogCrop,
> -                                                        xSize_, ySize_);
> +       lsc::ComponentsMap shadingData = algo_->sampleForCrop(configInfo.analogCrop,
> +                                                             xSize_, ySize_);
>         sets_.setData(std::move(shadingData));
>  
>         context.activeState.lsc.enabled = true;
> @@ -452,7 +452,7 @@ void LensShadingCorrection::setParameters(rkisp1_cif_isp_lsc_config &config)
>  }
>  
>  void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,
> -                                     const Components &set)
> +                                     const lsc::Components &set)
>  {
>         std::copy(set.r.begin(), set.r.end(), &config.r_data_tbl[0][0]);
>         std::copy(set.gr.begin(), set.gr.end(), &config.gr_data_tbl[0][0]);
> @@ -518,7 +518,7 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context,
>  
>         setParameters(*config);
>  
> -       const Components &set = sets_.getInterpolated(quantizedCt);
> +       const lsc::Components &set = sets_.getInterpolated(quantizedCt);
>         copyTable(*config, set);
>  
>         lastAppliedCt_ = ct;
> diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h
> index 3463531f2ab2..b21c91c0d81f 100644
> --- a/src/ipa/rkisp1/algorithms/lsc.h
> +++ b/src/ipa/rkisp1/algorithms/lsc.h
> @@ -11,6 +11,7 @@
>  #include <memory>
>  
>  #include "libipa/interpolator.h"
> +#include "libipa/lsc_base.h"
>  
>  #include "algorithm.h"
>  
> @@ -18,20 +19,9 @@ namespace libcamera {
>  
>  namespace ipa::rkisp1::algorithms {
>  
> -class LscImplementation;
> -
>  class LensShadingCorrection : public Algorithm
>  {
>  public:
> -       struct Components {
> -               std::vector<uint16_t> r;
> -               std::vector<uint16_t> gr;
> -               std::vector<uint16_t> gb;
> -               std::vector<uint16_t> b;
> -       };
> -
> -       using ComponentsMap = std::map<unsigned int, Components>;
> -
>         LensShadingCorrection();
>         ~LensShadingCorrection() = default;
>  
> @@ -49,7 +39,7 @@ public:
>                      ControlList &metadata) override;
>  private:
>         void setParameters(rkisp1_cif_isp_lsc_config &config);
> -       void copyTable(rkisp1_cif_isp_lsc_config &config, const Components &set0);
> +       void copyTable(rkisp1_cif_isp_lsc_config &config, const lsc::Components &set0);
>  
>         std::vector<double> xSize_;
>         std::vector<double> ySize_;
> @@ -61,23 +51,10 @@ private:
>         unsigned int lastAppliedCt_;
>         unsigned int lastAppliedQuantizedCt_;
>  
> -       ipa::Interpolator<Components> sets_;
> +       ipa::Interpolator<lsc::Components> sets_;
>  
>         std::unique_ptr<LscImplementation> algo_;
>  };
>  
> -class LscImplementation
> -{
> -public:
> -       virtual ~LscImplementation() {}
> -
> -       virtual int parseLscData(const ValueNode &sets) = 0;
> -
> -       virtual LensShadingCorrection::ComponentsMap
> -       sampleForCrop(const Rectangle &cropRectangle,
> -                     Span<const double> xSizes,
> -                     Span<const double> ySizes) = 0;
> -};
> -
>  } /* namespace ipa::rkisp1::algorithms */
>  } /* namespace libcamera */
> 
> -- 
> 2.54.0
>
Stefan Klug July 13, 2026, 1:17 p.m. UTC | #2
Hi Jacopo,

Quoting Jacopo Mondi (2026-07-08 17:50:52)
> Group in an header file part of libipa the definition of the lsc
> Components and the LscImplementation interface definition.
> 
> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> ---
>  src/ipa/libipa/lsc_base.cpp       | 95 +++++++++++++++++++++++++++++++++++++++
>  src/ipa/libipa/lsc_base.h         | 53 ++++++++++++++++++++++
>  src/ipa/libipa/meson.build        |  2 +
>  src/ipa/rkisp1/algorithms/lsc.cpp | 28 ++++++------
>  src/ipa/rkisp1/algorithms/lsc.h   | 29 ++----------
>  5 files changed, 167 insertions(+), 40 deletions(-)
> 
> diff --git a/src/ipa/libipa/lsc_base.cpp b/src/ipa/libipa/lsc_base.cpp
> new file mode 100644
> index 000000000000..d05075b988d7
> --- /dev/null
> +++ b/src/ipa/libipa/lsc_base.cpp
> @@ -0,0 +1,95 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2026 Ideas on Board Oy
> + *
> + * Base classes and types for LSC algorithms implementations
> + */
> +
> +#include "lsc_base.h"
> +
> +/**
> + * \file lsc_base.h
> + * \brief Base types and definitions for LscImplementation class hierarchy
> + */
> +
> +namespace libcamera {
> +
> +namespace ipa {
> +
> +namespace lsc {
> +
> +/**
> + * \struct Components
> + * \brief Associate a colour components with a list of gains
> + *
> + * LSC tables are defined as a list of gain values associated to a colour
> + * component.
> + *
> + * \var Components::r
> + * \brief The list of gains for the Red colour component
> + *
> + * \var Components::gr
> + * \brief The list of gains for the Green/Red colour component
> + *
> + * \var Components::gb
> + * \brief The list of gains for the Green/Blue colour component
> + *
> + * \var Components::b
> + * \brief The list of gains for the Blue colour component
> + */
> +
> +/**
> + * \typedef ComponentsMap
> + * \brief Associate a colour temperature to a LSC table
> + *
> + * An LSC table is generated during the tuning phase for a specific light

nit: We use colour temperature everywhere.

I read the comments from Kieran and have aside from tha, nothing to add.

Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>

Best regards,
Stefan

> + * temperature, and a tuning file usually contains LSC tables generated for
> + * several different colour temperatures.
> + */
> +
> +} /* namespace lsc */
> +
> +/**
> + * \class LscImplementation
> + * \brief Pure virtual base class for LSC algorithm implementations
> + *
> + * Defines the interface for the LSC algorithm implementation.
> + */
> +
> +/**
> + * \fn LscImplementation::~LscImplementation
> + * \brief Virtual class destructor
> + */
> +
> +/**
> + * \fn LscImplementation::parseLscData
> + * \brief Parse \a tuningData
> + * \param[in] tuningData The tuning data
> + *
> + * \return 0 on success, a negative error number otherwise
> + */
> +
> +/**
> + * \fn LscImplementation::sampleForCrop
> + * \brief Re-sample the LSC components for \a cropRectangle
> + * \param[in] cropRectangle The sensor analogue crop rectangle
> + * \param[in] xSizes List of horizontal positions of the LSC grid nodes
> + * \param[in] ySizes List of vertical positions of the LSC grid nodes
> + *
> + * LSC tables have to be re-sampled every time a new sensor configuration is
> + * used, as each streaming session might use a different sensor crop rectangle
> + * \a cropRectangle.
> + *
> + * \a cropRectangle represents the size of the frame on which the LSC tables
> + * have to be re-sampled on.
> + *
> + * \a xSizes and \a ySizes represent the position of the grid nodes vertexes in
> + * the [0, 1] interval. In example an equally spaced grid of 16 nodes will have
> + * each segment of size 0.0625 and the list of nodes position will be
> + * [0, 0.0625, 0.125, 0.1875, ... , 1]. It is expected that the first position
> + * is 0 and the last position is 1.
> + */
> +
> +} /* namespace ipa */
> +
> +} /* namespace libcamera */
> diff --git a/src/ipa/libipa/lsc_base.h b/src/ipa/libipa/lsc_base.h
> new file mode 100644
> index 000000000000..93f819d3c2af
> --- /dev/null
> +++ b/src/ipa/libipa/lsc_base.h
> @@ -0,0 +1,53 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2026 Ideas on Board Oy
> + *
> + * Base classes and types for LSC algorithms implementations
> + */
> +
> +#pragma once
> +
> +#include <map>
> +#include <stdint.h>
> +#include <string>
> +#include <vector>
> +
> +#include <libcamera/base/span.h>
> +
> +#include <libcamera/geometry.h>
> +
> +#include "libcamera/internal/value_node.h"
> +
> +namespace libcamera {
> +
> +namespace ipa {
> +
> +namespace lsc {
> +
> +struct Components {
> +       std::vector<uint16_t> r;
> +       std::vector<uint16_t> gr;
> +       std::vector<uint16_t> gb;
> +       std::vector<uint16_t> b;
> +};
> +
> +using ComponentsMap = std::map<unsigned int, Components>;
> +
> +} /* namespace lsc */
> +
> +class LscImplementation
> +{
> +public:
> +       virtual ~LscImplementation() {}
> +
> +       virtual int parseLscData(const ValueNode &tuningData) = 0;
> +
> +       virtual lsc::ComponentsMap
> +       sampleForCrop(const Rectangle &cropRectangle,
> +                     Span<const double> xSizes,
> +                     Span<const double> ySizes) = 0;
> +};
> +
> +} /* namespace ipa */
> +
> +} /* namespace libcamera */
> diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
> index edf8eabd8b78..96611e90ee1e 100644
> --- a/src/ipa/libipa/meson.build
> +++ b/src/ipa/libipa/meson.build
> @@ -14,6 +14,7 @@ libipa_headers = files([
>      'fixedpoint.h',
>      'histogram.h',
>      'interpolator.h',
> +    'lsc_base.h',
>      'lsc_polynomial.h',
>      'lux.h',
>      'module.h',
> @@ -36,6 +37,7 @@ libipa_sources = files([
>      'fixedpoint.cpp',
>      'histogram.cpp',
>      'interpolator.cpp',
> +    'lsc_base.cpp',
>      'lsc_polynomial.cpp',
>      'lux.cpp',
>      'module.cpp',
> diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp
> index 38380aa839c6..af919f7429af 100644
> --- a/src/ipa/rkisp1/algorithms/lsc.cpp
> +++ b/src/ipa/rkisp1/algorithms/lsc.cpp
> @@ -38,10 +38,10 @@ void interpolateVector(const std::vector<T> &a, const std::vector<T> &b,
>  }
>  
>  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,
> +void Interpolator<lsc::Components>::
> +       interpolate(const lsc::Components &a,
> +                   const lsc::Components &b,
> +                   lsc::Components &dest,
>                     double lambda)
>  {
>         interpolateVector(a.r, b.r, dest.r, lambda);
> @@ -80,7 +80,7 @@ public:
>  
>         int parseLscData(const ValueNode &sets) override;
>  
> -       LensShadingCorrection::ComponentsMap
> +       lsc::ComponentsMap
>         sampleForCrop(const Rectangle &cropRectangle,
>                       Span<const double> xSizes,
>                       Span<const double> ySizes) override;
> @@ -138,7 +138,7 @@ int LscPolynomialImpl::parseLscData(const ValueNode &sets)
>         return 0;
>  }
>  
> -LensShadingCorrection::ComponentsMap
> +lsc::ComponentsMap
>  LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle,
>                                  Span<const double> xSizes,
>                                  Span<const double> ySizes)
> @@ -146,7 +146,7 @@ LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle,
>         std::vector<double> xPos = sizesListToPositions(xSizes);
>         std::vector<double> yPos = sizesListToPositions(ySizes);
>  
> -       LensShadingCorrection::ComponentsMap components;
> +       lsc::ComponentsMap components;
>  
>         for (const auto &[k, p] : lscData_) {
>                 components[k] = {
> @@ -226,7 +226,7 @@ class LscTableImpl : public LscImplementation
>  public:
>         int parseLscData(const ValueNode &sets) override;
>  
> -       LensShadingCorrection::ComponentsMap
> +       lsc::ComponentsMap
>         sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,
>                       [[maybe_unused]] Span<const double> xSizes,
>                       [[maybe_unused]] Span<const double> ySizes) override
> @@ -240,7 +240,7 @@ private:
>         std::vector<uint16_t> parseTable(const ValueNode &tuningData,
>                                          const char *prop);
>  
> -       LensShadingCorrection::ComponentsMap lscData_;
> +       lsc::ComponentsMap lscData_;
>  };
>  
>  int LscTableImpl::parseLscData(const ValueNode &sets)
> @@ -255,7 +255,7 @@ int LscTableImpl::parseLscData(const ValueNode &sets)
>                         return -EINVAL;
>                 }
>  
> -               LensShadingCorrection::Components components;
> +               lsc::Components components;
>                 components.r = parseTable(set, "r");
>                 components.gr = parseTable(set, "gr");
>                 components.gb = parseTable(set, "gb");
> @@ -435,8 +435,8 @@ int LensShadingCorrection::configure(IPAContext &context,
>         }
>  
>         LOG(RkISP1Lsc, Debug) << "Sample LSC data for " << configInfo.analogCrop;
> -       ComponentsMap shadingData = algo_->sampleForCrop(configInfo.analogCrop,
> -                                                        xSize_, ySize_);
> +       lsc::ComponentsMap shadingData = algo_->sampleForCrop(configInfo.analogCrop,
> +                                                             xSize_, ySize_);
>         sets_.setData(std::move(shadingData));
>  
>         context.activeState.lsc.enabled = true;
> @@ -452,7 +452,7 @@ void LensShadingCorrection::setParameters(rkisp1_cif_isp_lsc_config &config)
>  }
>  
>  void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,
> -                                     const Components &set)
> +                                     const lsc::Components &set)
>  {
>         std::copy(set.r.begin(), set.r.end(), &config.r_data_tbl[0][0]);
>         std::copy(set.gr.begin(), set.gr.end(), &config.gr_data_tbl[0][0]);
> @@ -518,7 +518,7 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context,
>  
>         setParameters(*config);
>  
> -       const Components &set = sets_.getInterpolated(quantizedCt);
> +       const lsc::Components &set = sets_.getInterpolated(quantizedCt);
>         copyTable(*config, set);
>  
>         lastAppliedCt_ = ct;
> diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h
> index 3463531f2ab2..b21c91c0d81f 100644
> --- a/src/ipa/rkisp1/algorithms/lsc.h
> +++ b/src/ipa/rkisp1/algorithms/lsc.h
> @@ -11,6 +11,7 @@
>  #include <memory>
>  
>  #include "libipa/interpolator.h"
> +#include "libipa/lsc_base.h"
>  
>  #include "algorithm.h"
>  
> @@ -18,20 +19,9 @@ namespace libcamera {
>  
>  namespace ipa::rkisp1::algorithms {
>  
> -class LscImplementation;
> -
>  class LensShadingCorrection : public Algorithm
>  {
>  public:
> -       struct Components {
> -               std::vector<uint16_t> r;
> -               std::vector<uint16_t> gr;
> -               std::vector<uint16_t> gb;
> -               std::vector<uint16_t> b;
> -       };
> -
> -       using ComponentsMap = std::map<unsigned int, Components>;
> -
>         LensShadingCorrection();
>         ~LensShadingCorrection() = default;
>  
> @@ -49,7 +39,7 @@ public:
>                      ControlList &metadata) override;
>  private:
>         void setParameters(rkisp1_cif_isp_lsc_config &config);
> -       void copyTable(rkisp1_cif_isp_lsc_config &config, const Components &set0);
> +       void copyTable(rkisp1_cif_isp_lsc_config &config, const lsc::Components &set0);
>  
>         std::vector<double> xSize_;
>         std::vector<double> ySize_;
> @@ -61,23 +51,10 @@ private:
>         unsigned int lastAppliedCt_;
>         unsigned int lastAppliedQuantizedCt_;
>  
> -       ipa::Interpolator<Components> sets_;
> +       ipa::Interpolator<lsc::Components> sets_;
>  
>         std::unique_ptr<LscImplementation> algo_;
>  };
>  
> -class LscImplementation
> -{
> -public:
> -       virtual ~LscImplementation() {}
> -
> -       virtual int parseLscData(const ValueNode &sets) = 0;
> -
> -       virtual LensShadingCorrection::ComponentsMap
> -       sampleForCrop(const Rectangle &cropRectangle,
> -                     Span<const double> xSizes,
> -                     Span<const double> ySizes) = 0;
> -};
> -
>  } /* namespace ipa::rkisp1::algorithms */
>  } /* namespace libcamera */
> 
> -- 
> 2.54.0
>

Patch
diff mbox series

diff --git a/src/ipa/libipa/lsc_base.cpp b/src/ipa/libipa/lsc_base.cpp
new file mode 100644
index 000000000000..d05075b988d7
--- /dev/null
+++ b/src/ipa/libipa/lsc_base.cpp
@@ -0,0 +1,95 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026 Ideas on Board Oy
+ *
+ * Base classes and types for LSC algorithms implementations
+ */
+
+#include "lsc_base.h"
+
+/**
+ * \file lsc_base.h
+ * \brief Base types and definitions for LscImplementation class hierarchy
+ */
+
+namespace libcamera {
+
+namespace ipa {
+
+namespace lsc {
+
+/**
+ * \struct Components
+ * \brief Associate a colour components with a list of gains
+ *
+ * LSC tables are defined as a list of gain values associated to a colour
+ * component.
+ *
+ * \var Components::r
+ * \brief The list of gains for the Red colour component
+ *
+ * \var Components::gr
+ * \brief The list of gains for the Green/Red colour component
+ *
+ * \var Components::gb
+ * \brief The list of gains for the Green/Blue colour component
+ *
+ * \var Components::b
+ * \brief The list of gains for the Blue colour component
+ */
+
+/**
+ * \typedef ComponentsMap
+ * \brief Associate a colour temperature to a LSC table
+ *
+ * An LSC table is generated during the tuning phase for a specific light
+ * temperature, and a tuning file usually contains LSC tables generated for
+ * several different colour temperatures.
+ */
+
+} /* namespace lsc */
+
+/**
+ * \class LscImplementation
+ * \brief Pure virtual base class for LSC algorithm implementations
+ *
+ * Defines the interface for the LSC algorithm implementation.
+ */
+
+/**
+ * \fn LscImplementation::~LscImplementation
+ * \brief Virtual class destructor
+ */
+
+/**
+ * \fn LscImplementation::parseLscData
+ * \brief Parse \a tuningData
+ * \param[in] tuningData The tuning data
+ *
+ * \return 0 on success, a negative error number otherwise
+ */
+
+/**
+ * \fn LscImplementation::sampleForCrop
+ * \brief Re-sample the LSC components for \a cropRectangle
+ * \param[in] cropRectangle The sensor analogue crop rectangle
+ * \param[in] xSizes List of horizontal positions of the LSC grid nodes
+ * \param[in] ySizes List of vertical positions of the LSC grid nodes
+ *
+ * LSC tables have to be re-sampled every time a new sensor configuration is
+ * used, as each streaming session might use a different sensor crop rectangle
+ * \a cropRectangle.
+ *
+ * \a cropRectangle represents the size of the frame on which the LSC tables
+ * have to be re-sampled on.
+ *
+ * \a xSizes and \a ySizes represent the position of the grid nodes vertexes in
+ * the [0, 1] interval. In example an equally spaced grid of 16 nodes will have
+ * each segment of size 0.0625 and the list of nodes position will be
+ * [0, 0.0625, 0.125, 0.1875, ... , 1]. It is expected that the first position
+ * is 0 and the last position is 1.
+ */
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
diff --git a/src/ipa/libipa/lsc_base.h b/src/ipa/libipa/lsc_base.h
new file mode 100644
index 000000000000..93f819d3c2af
--- /dev/null
+++ b/src/ipa/libipa/lsc_base.h
@@ -0,0 +1,53 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026 Ideas on Board Oy
+ *
+ * Base classes and types for LSC algorithms implementations
+ */
+
+#pragma once
+
+#include <map>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include <libcamera/base/span.h>
+
+#include <libcamera/geometry.h>
+
+#include "libcamera/internal/value_node.h"
+
+namespace libcamera {
+
+namespace ipa {
+
+namespace lsc {
+
+struct Components {
+	std::vector<uint16_t> r;
+	std::vector<uint16_t> gr;
+	std::vector<uint16_t> gb;
+	std::vector<uint16_t> b;
+};
+
+using ComponentsMap = std::map<unsigned int, Components>;
+
+} /* namespace lsc */
+
+class LscImplementation
+{
+public:
+	virtual ~LscImplementation() {}
+
+	virtual int parseLscData(const ValueNode &tuningData) = 0;
+
+	virtual lsc::ComponentsMap
+	sampleForCrop(const Rectangle &cropRectangle,
+		      Span<const double> xSizes,
+		      Span<const double> ySizes) = 0;
+};
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
index edf8eabd8b78..96611e90ee1e 100644
--- a/src/ipa/libipa/meson.build
+++ b/src/ipa/libipa/meson.build
@@ -14,6 +14,7 @@  libipa_headers = files([
     'fixedpoint.h',
     'histogram.h',
     'interpolator.h',
+    'lsc_base.h',
     'lsc_polynomial.h',
     'lux.h',
     'module.h',
@@ -36,6 +37,7 @@  libipa_sources = files([
     'fixedpoint.cpp',
     'histogram.cpp',
     'interpolator.cpp',
+    'lsc_base.cpp',
     'lsc_polynomial.cpp',
     'lux.cpp',
     'module.cpp',
diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp
index 38380aa839c6..af919f7429af 100644
--- a/src/ipa/rkisp1/algorithms/lsc.cpp
+++ b/src/ipa/rkisp1/algorithms/lsc.cpp
@@ -38,10 +38,10 @@  void interpolateVector(const std::vector<T> &a, const std::vector<T> &b,
 }
 
 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,
+void Interpolator<lsc::Components>::
+	interpolate(const lsc::Components &a,
+		    const lsc::Components &b,
+		    lsc::Components &dest,
 		    double lambda)
 {
 	interpolateVector(a.r, b.r, dest.r, lambda);
@@ -80,7 +80,7 @@  public:
 
 	int parseLscData(const ValueNode &sets) override;
 
-	LensShadingCorrection::ComponentsMap
+	lsc::ComponentsMap
 	sampleForCrop(const Rectangle &cropRectangle,
 		      Span<const double> xSizes,
 		      Span<const double> ySizes) override;
@@ -138,7 +138,7 @@  int LscPolynomialImpl::parseLscData(const ValueNode &sets)
 	return 0;
 }
 
-LensShadingCorrection::ComponentsMap
+lsc::ComponentsMap
 LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle,
 				 Span<const double> xSizes,
 				 Span<const double> ySizes)
@@ -146,7 +146,7 @@  LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle,
 	std::vector<double> xPos = sizesListToPositions(xSizes);
 	std::vector<double> yPos = sizesListToPositions(ySizes);
 
-	LensShadingCorrection::ComponentsMap components;
+	lsc::ComponentsMap components;
 
 	for (const auto &[k, p] : lscData_) {
 		components[k] = {
@@ -226,7 +226,7 @@  class LscTableImpl : public LscImplementation
 public:
 	int parseLscData(const ValueNode &sets) override;
 
-	LensShadingCorrection::ComponentsMap
+	lsc::ComponentsMap
 	sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,
 		      [[maybe_unused]] Span<const double> xSizes,
 		      [[maybe_unused]] Span<const double> ySizes) override
@@ -240,7 +240,7 @@  private:
 	std::vector<uint16_t> parseTable(const ValueNode &tuningData,
 					 const char *prop);
 
-	LensShadingCorrection::ComponentsMap lscData_;
+	lsc::ComponentsMap lscData_;
 };
 
 int LscTableImpl::parseLscData(const ValueNode &sets)
@@ -255,7 +255,7 @@  int LscTableImpl::parseLscData(const ValueNode &sets)
 			return -EINVAL;
 		}
 
-		LensShadingCorrection::Components components;
+		lsc::Components components;
 		components.r = parseTable(set, "r");
 		components.gr = parseTable(set, "gr");
 		components.gb = parseTable(set, "gb");
@@ -435,8 +435,8 @@  int LensShadingCorrection::configure(IPAContext &context,
 	}
 
 	LOG(RkISP1Lsc, Debug) << "Sample LSC data for " << configInfo.analogCrop;
-	ComponentsMap shadingData = algo_->sampleForCrop(configInfo.analogCrop,
-							 xSize_, ySize_);
+	lsc::ComponentsMap shadingData = algo_->sampleForCrop(configInfo.analogCrop,
+							      xSize_, ySize_);
 	sets_.setData(std::move(shadingData));
 
 	context.activeState.lsc.enabled = true;
@@ -452,7 +452,7 @@  void LensShadingCorrection::setParameters(rkisp1_cif_isp_lsc_config &config)
 }
 
 void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,
-				      const Components &set)
+				      const lsc::Components &set)
 {
 	std::copy(set.r.begin(), set.r.end(), &config.r_data_tbl[0][0]);
 	std::copy(set.gr.begin(), set.gr.end(), &config.gr_data_tbl[0][0]);
@@ -518,7 +518,7 @@  void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context,
 
 	setParameters(*config);
 
-	const Components &set = sets_.getInterpolated(quantizedCt);
+	const lsc::Components &set = sets_.getInterpolated(quantizedCt);
 	copyTable(*config, set);
 
 	lastAppliedCt_ = ct;
diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h
index 3463531f2ab2..b21c91c0d81f 100644
--- a/src/ipa/rkisp1/algorithms/lsc.h
+++ b/src/ipa/rkisp1/algorithms/lsc.h
@@ -11,6 +11,7 @@ 
 #include <memory>
 
 #include "libipa/interpolator.h"
+#include "libipa/lsc_base.h"
 
 #include "algorithm.h"
 
@@ -18,20 +19,9 @@  namespace libcamera {
 
 namespace ipa::rkisp1::algorithms {
 
-class LscImplementation;
-
 class LensShadingCorrection : public Algorithm
 {
 public:
-	struct Components {
-		std::vector<uint16_t> r;
-		std::vector<uint16_t> gr;
-		std::vector<uint16_t> gb;
-		std::vector<uint16_t> b;
-	};
-
-	using ComponentsMap = std::map<unsigned int, Components>;
-
 	LensShadingCorrection();
 	~LensShadingCorrection() = default;
 
@@ -49,7 +39,7 @@  public:
 		     ControlList &metadata) override;
 private:
 	void setParameters(rkisp1_cif_isp_lsc_config &config);
-	void copyTable(rkisp1_cif_isp_lsc_config &config, const Components &set0);
+	void copyTable(rkisp1_cif_isp_lsc_config &config, const lsc::Components &set0);
 
 	std::vector<double> xSize_;
 	std::vector<double> ySize_;
@@ -61,23 +51,10 @@  private:
 	unsigned int lastAppliedCt_;
 	unsigned int lastAppliedQuantizedCt_;
 
-	ipa::Interpolator<Components> sets_;
+	ipa::Interpolator<lsc::Components> sets_;
 
 	std::unique_ptr<LscImplementation> algo_;
 };
 
-class LscImplementation
-{
-public:
-	virtual ~LscImplementation() {}
-
-	virtual int parseLscData(const ValueNode &sets) = 0;
-
-	virtual LensShadingCorrection::ComponentsMap
-	sampleForCrop(const Rectangle &cropRectangle,
-		      Span<const double> xSizes,
-		      Span<const double> ySizes) = 0;
-};
-
 } /* namespace ipa::rkisp1::algorithms */
 } /* namespace libcamera */