[v5,23/36] ipa: libipa: lsc: Introduce LscAlgorithm
diff mbox series

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

Commit Message

Jacopo Mondi July 8, 2026, 3:51 p.m. UTC
Introduce the LscAlgorithm class that implements the LSC algorithm
for libipa.

The class uses two backends (LscPolynomial and LscTable) to perform
tuning file parsing and re-scaling of the LSC gains.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 src/ipa/libipa/lsc.cpp | 209 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/ipa/libipa/lsc.h   |  42 ++++++++++
 2 files changed, 251 insertions(+)

Comments

Kieran Bingham July 14, 2026, 5:10 p.m. UTC | #1
Quoting Jacopo Mondi (2026-07-08 16:51:05)
> Introduce the LscAlgorithm class that implements the LSC algorithm
> for libipa.
> 
> The class uses two backends (LscPolynomial and LscTable) to perform
> tuning file parsing and re-scaling of the LSC gains.
> 
> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> ---
>  src/ipa/libipa/lsc.cpp | 209 +++++++++++++++++++++++++++++++++++++++++++++++++
>  src/ipa/libipa/lsc.h   |  42 ++++++++++
>  2 files changed, 251 insertions(+)
> 
> diff --git a/src/ipa/libipa/lsc.cpp b/src/ipa/libipa/lsc.cpp
> index 382cafc04ab4..cf748b766d1a 100644
> --- a/src/ipa/libipa/lsc.cpp
> +++ b/src/ipa/libipa/lsc.cpp
> @@ -7,6 +7,13 @@
>  
>  #include "lsc.h"
>  
> +#include <libcamera/base/log.h>
> +
> +#include <libcamera/control_ids.h>
> +
> +#include "lsc_polynomial.h"
> +#include "lsc_table.h"
> +
>  /**
>   * \file lsc.h
>   * \brief libipa LSC algorithm
> @@ -14,6 +21,8 @@
>  
>  namespace libcamera {
>  
> +LOG_DEFINE_CATEGORY(Lsc)
> +
>  namespace ipa {
>  
>  namespace lsc {
> @@ -39,6 +48,206 @@ namespace lsc {
>  
>  } /* namespace lsc */
>  
> +/**
> + * \class LscAlgorithm
> + * \brief libIPA LSC algorithm implementation
> + *
> + * Due to the optical characteristics of the lens, the light intensity received
> + * by the sensor is not uniform. The Lens Shading Correction algorithm applies
> + * multipliers to all pixels to compensate for the lens shading effect.
> + *
> + * The LscAlgorithm implements the libipa Lens Shading Correction algorithm
> + * using an implementation of the LscImplementation interface.
> + *
> + * It provides support for parsing the tuning file content and generates tables
> + * of per-colour temperature gains that IPA algorithms can use to program their

hrm this sounds like it's per colour - which have temperature gains.
Reworking seems awkward to do with just adjusting a '-'. Trying deeper:

"""
This class provides support for parsing the tuning file content and
generates tables indexed by colour temperature to store per-channel
gains for the IPA algorithm to be able to program the LSC engine.
"""

Maybe that's too much - but it's only the 'per-colour' part that I'm
worried about!


> + * LSC engine.
> + *
> + * The init() function parses the tuning file and loads the gain tables either
> + * in tabular form (LscTable) or as radial polynomials (LscPolynomial). The gain
> + * tables are organized per-colour temperature with per-colour components gain
> + * vectors or polynomial coefficients.

Oh it sneaks in here again too.

> + *
> + * At LscAlgorithm::configure() time the LSC tables are re-sampled on the
> + * sensor's crop rectangle in use to adapt them to the configuration in use for
> + * a streaming session. Polynomial LSC tables support re-sampling and can be
> + * applied to any sensor configuration. Grid-based LSC tables cannot currently
> + * be re-sampled and the configuration as parsed from the tuning file is used
> + * for all sensor configurations providing best-effort results.
> + *
> + * \todo: Implement grid based re-sampling

No colon needed on the \todo

> + *
> + * When the IPA algorithms wants to get access to the (re-sampled) tables to
> + * program its LSC engine, it uses LscAlgorithm::interpolateComponents() to get
> + * an LSC table interpolated by the LscAlgorithm class for the specified colour
> + * temperature. If the algorithm wants to access the non-interpolated tables it
> + * can retrieve them using LscAlgorithm::getComponents().
> + */
> +
> +/**
> + * \param[in] tuningData The tuning data
> + * \param[in] sensorSize The physical sensor size
> + * \param[in] controls The IPA list of supported controls
> + *
> + * Parse \a tuningData according to the settings specified in \a descriptor to
> + * populate the LSC data and registers LSC controls in \a controls.
> + *
> + * \return 0 on success, a negative error code otherwise
> + */
> +int LscAlgorithm::init(const ValueNode &tuningData, const Size &sensorSize,
> +                      ControlInfoMap::Map &controls)
> +{
> +       polynomial_ = false;
> +
> +       std::string type = tuningData["type"].get<std::string>("table");
> +       if (type == "table") {
> +               impl_ = std::make_unique<LscTable>();
> +               LOG(Lsc, Debug) << "Using table-based Lsc";
> +       } else if (type == "polynomial") {
> +               /*
> +                * \todo: Most likely the reference frame should be native_size.

no colon


> +                * Let's wait how the internal discussions progress.
> +                */
> +               impl_ = std::make_unique<LscPolynomial>(sensorSize);
> +               polynomial_ = true;
> +               LOG(Lsc, Debug) << "Using polynomial Lsc";
> +       } else {
> +               LOG(Lsc, Error) << "Unsupported Lsc algorithm '"
> +                               << type << "'";
> +               return -EINVAL;
> +       }
> +
> +       const ValueNode &yamlSets = tuningData["sets"];
> +       if (!yamlSets.isList()) {
> +               LOG(Lsc, Error) << "'sets' parameter not found in tuning file";
> +               return -EINVAL;
> +       }
> +
> +       int ret = impl_->parseLscData(yamlSets);
> +       if (ret)
> +               return ret;
> +
> +       controls[&controls::LensShadingCorrectionEnable] =
> +               ControlInfo(false, true, true);
> +
> +       return 0;
> +}
> +
> +/**
> + * \param[in] state The LSC active state
> + * \param[in] analogCrop The current sensor analog crop rectangle
> + * \param[in] xPos List of horizontal positions of the LSC grid nodes
> + * \param[in] yPos List of vertical positions of the LSC grid nodes
> + *
> + * Re-sample the LSC data for an \a analogCrop.
> + *
> + * LSC tables are generated at tuning time using a known sensor configuration.
> + * When a new streaming session is started, it might use a different sensor
> + * configuration for which the LSC tables need to be adjusted to.
> + *
> + * This function re-generates the LSC tables to adapt them to a new sensor
> + * configuration, specifically it re-samples the LSC data for a new \a
> + * analogCrop on a grid specified by \a xPos and \a yPos. Re-sampling of
> + * LSC data is currently supported by polynomial-based LSC tables.
> + *
> + * \sa LscImplementation::sampleForCrop
> + *
> + * \return 0 on success, a negative error code otherwise
> + */
> +int LscAlgorithm::configure(lsc::ActiveState &state, const Rectangle &analogCrop,
> +                           const std::vector<double> &xPos,
> +                           const std::vector<double> &yPos)
> +{
> +       LOG(Lsc, Debug) << "Sample Lsc data for " << analogCrop;
> +       lsc::ComponentsMap lscData =
> +               impl_->sampleForCrop(analogCrop, xPos, yPos);
> +
> +       /*
> +        * Retain a copy of the components table.
> +        *
> +        * We could avoid a copy here if getComponents() could
> +        * return sets_.data() but I wasn't able to work around the
> +        * compiler refusing it.
> +        */
> +       lscData_ = lscData;
> +
> +       sets_.setData(std::move(lscData));
> +       state.enabled = true;
> +
> +       return 0;
> +}
> +
> +/**
> + * \brief Queue a request to the lsc algorithm
> + * \param[in] state The lsc active state
> + * \param[in] context The lsc frame context
> + * \param[in] controls The list of controls associated with a Request
> + *
> + * Queue a new list of \a controls to the lsc algorithm.
> + * The only supported control is controls::LensShadingCorrectionEnable.
> + */
> +void LscAlgorithm::queueRequest(lsc::ActiveState &state,
> +                               lsc::FrameContext &context,
> +                               const ControlList &controls)
> +{
> +       const auto &lscEnable = controls.get(controls::LensShadingCorrectionEnable);
> +       if (lscEnable && *lscEnable != state.enabled) {
> +               state.enabled = *lscEnable;
> +
> +               LOG(Lsc, Debug)
> +                       << (state.enabled ? "Enabling" : "Disabling") << " Lsc";
> +
> +               context.update = true;
> +       }
> +
> +       context.enabled = state.enabled;
> +}
> +
> +/**
> + * \brief Populate the list of lsc metadata
> + * \param[in] context The lsc frame context
> + * \param[in] metadata The list of metadata
> + *
> + * Populates the list of \a metadata with controls handled by the LscAlgorithm
> + * class. The only supported metadata is controls::LensShadingCorrectionEnable.
> + */
> +void LscAlgorithm::process(lsc::FrameContext &context, ControlList &metadata)
> +{
> +       metadata.set(controls::LensShadingCorrectionEnable, context.enabled);
> +}
> +
> +/**
> + * \fn LscAlgorithm::interpolateComponents
> + * \brief Interpolate the LSC tables for a given colour temperature
> + * \param[in] ct The colour temperature
> + *
> + * LSC tables are generated using different colour temperatures during the
> + * tuning phase.
> + *
> + * This function returns the interpolated LSC data for a given \a ct
> + * colour temperature.
> + *
> + * IPA algorithm can use this function to obtain a list of gains per-colour
> + * component to program their LSC engines with every time a significant enough

If we're reworking, "a list of per-colour component gains" sounds better
... I don't know what grammar rule makes it that way - but it just seems
like it should be that way around ;-)

But we have the same issue as we had with 'per-colour temperature' maybe
it needs to be:

  of per-colour-component gains ?
 




> + * change in colour temperature is detected.
> + *
> + * Calling this function is only valid after LscAlgorithm::configure() has been
> + * called. An empty components list is returned otherwise.
> + *
> + * \return The LSC gains table interpolated for temperature \a ct
> + */
> +
> +/**
> + * \fn LscAlgorithm::getComponents
> + *
> + * Return the map of LSC data per colour temperature.
> + *
> + * Calling this function is only valid after LscAlgorithm::configure() has been
> + * called. An empty components list is returned otherwise.
> + *
> + * \return The map of LSC gains tables per colour-temperature

I think throughout the use of 'per' and then 'two words' needs to be
normalised to be consistent.


With that:


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

> + */
> +
>  } /* namespace ipa */
>  
>  } /* namespace libcamera */
> diff --git a/src/ipa/libipa/lsc.h b/src/ipa/libipa/lsc.h
> index 73519564feff..9a51d32c3464 100644
> --- a/src/ipa/libipa/lsc.h
> +++ b/src/ipa/libipa/lsc.h
> @@ -7,6 +7,17 @@
>  
>  #pragma once
>  
> +#include <memory>
> +#include <vector>
> +
> +#include <libcamera/controls.h>
> +#include <libcamera/geometry.h>
> +
> +#include "libcamera/internal/value_node.h"
> +
> +#include "interpolator.h"
> +#include "lsc_base.h"
> +
>  namespace libcamera {
>  
>  namespace ipa {
> @@ -24,6 +35,37 @@ struct FrameContext {
>  
>  } /* namespace lsc */
>  
> +class LscAlgorithm
> +{
> +public:
> +       int init(const ValueNode &tuningData, const Size &sensorSize,
> +                ControlInfoMap::Map &controls);
> +
> +       int configure(lsc::ActiveState &state, const Rectangle &analogCrop,
> +                     const std::vector<double> &xPos,
> +                     const std::vector<double> &yPos);
> +
> +       void queueRequest(lsc::ActiveState &state, lsc::FrameContext &context,
> +                         const ControlList &controls);
> +       void process(lsc::FrameContext &context, ControlList &metadata);
> +
> +       const lsc::Components interpolateComponents(unsigned int ct)
> +       {
> +               return sets_.getInterpolated(ct);
> +       }
> +
> +       const lsc::ComponentsMap getComponents()
> +       {
> +               return lscData_;
> +       }
> +
> +private:
> +       std::unique_ptr<LscImplementation> impl_;
> +       Interpolator<lsc::Components> sets_;
> +       lsc::ComponentsMap lscData_;
> +       bool polynomial_;
> +};
> +
>  } /* namespace ipa */
>  
>  } /* namespace libcamera */
> 
> -- 
> 2.54.0
>
Barnabás Pőcze July 24, 2026, 3:40 p.m. UTC | #2
2026. 07. 08. 17:51 keltezéssel, Jacopo Mondi írta:
> Introduce the LscAlgorithm class that implements the LSC algorithm
> for libipa.
> 
> The class uses two backends (LscPolynomial and LscTable) to perform
> tuning file parsing and re-scaling of the LSC gains.
> 
> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> ---
>   src/ipa/libipa/lsc.cpp | 209 +++++++++++++++++++++++++++++++++++++++++++++++++
>   src/ipa/libipa/lsc.h   |  42 ++++++++++
>   2 files changed, 251 insertions(+)
> 
> [...]
> diff --git a/src/ipa/libipa/lsc.h b/src/ipa/libipa/lsc.h
> index 73519564feff..9a51d32c3464 100644
> --- a/src/ipa/libipa/lsc.h
> +++ b/src/ipa/libipa/lsc.h
> @@ -7,6 +7,17 @@
>   
>   #pragma once
>   
> +#include <memory>
> +#include <vector>
> +
> +#include <libcamera/controls.h>
> +#include <libcamera/geometry.h>
> +
> +#include "libcamera/internal/value_node.h"
> +
> +#include "interpolator.h"
> +#include "lsc_base.h"
> +
>   namespace libcamera {
>   
>   namespace ipa {
> @@ -24,6 +35,37 @@ struct FrameContext {
>   
>   } /* namespace lsc */
>   
> +class LscAlgorithm
> +{
> +public:
> +	int init(const ValueNode &tuningData, const Size &sensorSize,
> +		 ControlInfoMap::Map &controls);
> +
> +	int configure(lsc::ActiveState &state, const Rectangle &analogCrop,
> +		      const std::vector<double> &xPos,
> +		      const std::vector<double> &yPos);
> +
> +	void queueRequest(lsc::ActiveState &state, lsc::FrameContext &context,
> +			  const ControlList &controls);
> +	void process(lsc::FrameContext &context, ControlList &metadata);
> +
> +	const lsc::Components interpolateComponents(unsigned int ct)
> +	{
> +		return sets_.getInterpolated(ct);
> +	}
> +
> +	const lsc::ComponentsMap getComponents()
> +	{
> +		return lscData_;
> +	}
> +
> +private:
> +	std::unique_ptr<LscImplementation> impl_;
> +	Interpolator<lsc::Components> sets_;
> +	lsc::ComponentsMap lscData_;
> +	bool polynomial_;

This does not seem to be used anywhere?


> +};
> +
>   } /* namespace ipa */
>   
>   } /* namespace libcamera */
>

Patch
diff mbox series

diff --git a/src/ipa/libipa/lsc.cpp b/src/ipa/libipa/lsc.cpp
index 382cafc04ab4..cf748b766d1a 100644
--- a/src/ipa/libipa/lsc.cpp
+++ b/src/ipa/libipa/lsc.cpp
@@ -7,6 +7,13 @@ 
 
 #include "lsc.h"
 
+#include <libcamera/base/log.h>
+
+#include <libcamera/control_ids.h>
+
+#include "lsc_polynomial.h"
+#include "lsc_table.h"
+
 /**
  * \file lsc.h
  * \brief libipa LSC algorithm
@@ -14,6 +21,8 @@ 
 
 namespace libcamera {
 
+LOG_DEFINE_CATEGORY(Lsc)
+
 namespace ipa {
 
 namespace lsc {
@@ -39,6 +48,206 @@  namespace lsc {
 
 } /* namespace lsc */
 
+/**
+ * \class LscAlgorithm
+ * \brief libIPA LSC algorithm implementation
+ *
+ * Due to the optical characteristics of the lens, the light intensity received
+ * by the sensor is not uniform. The Lens Shading Correction algorithm applies
+ * multipliers to all pixels to compensate for the lens shading effect.
+ *
+ * The LscAlgorithm implements the libipa Lens Shading Correction algorithm
+ * using an implementation of the LscImplementation interface.
+ *
+ * It provides support for parsing the tuning file content and generates tables
+ * of per-colour temperature gains that IPA algorithms can use to program their
+ * LSC engine.
+ *
+ * The init() function parses the tuning file and loads the gain tables either
+ * in tabular form (LscTable) or as radial polynomials (LscPolynomial). The gain
+ * tables are organized per-colour temperature with per-colour components gain
+ * vectors or polynomial coefficients.
+ *
+ * At LscAlgorithm::configure() time the LSC tables are re-sampled on the
+ * sensor's crop rectangle in use to adapt them to the configuration in use for
+ * a streaming session. Polynomial LSC tables support re-sampling and can be
+ * applied to any sensor configuration. Grid-based LSC tables cannot currently
+ * be re-sampled and the configuration as parsed from the tuning file is used
+ * for all sensor configurations providing best-effort results.
+ *
+ * \todo: Implement grid based re-sampling
+ *
+ * When the IPA algorithms wants to get access to the (re-sampled) tables to
+ * program its LSC engine, it uses LscAlgorithm::interpolateComponents() to get
+ * an LSC table interpolated by the LscAlgorithm class for the specified colour
+ * temperature. If the algorithm wants to access the non-interpolated tables it
+ * can retrieve them using LscAlgorithm::getComponents().
+ */
+
+/**
+ * \param[in] tuningData The tuning data
+ * \param[in] sensorSize The physical sensor size
+ * \param[in] controls The IPA list of supported controls
+ *
+ * Parse \a tuningData according to the settings specified in \a descriptor to
+ * populate the LSC data and registers LSC controls in \a controls.
+ *
+ * \return 0 on success, a negative error code otherwise
+ */
+int LscAlgorithm::init(const ValueNode &tuningData, const Size &sensorSize,
+		       ControlInfoMap::Map &controls)
+{
+	polynomial_ = false;
+
+	std::string type = tuningData["type"].get<std::string>("table");
+	if (type == "table") {
+		impl_ = std::make_unique<LscTable>();
+		LOG(Lsc, Debug) << "Using table-based Lsc";
+	} else if (type == "polynomial") {
+		/*
+		 * \todo: Most likely the reference frame should be native_size.
+		 * Let's wait how the internal discussions progress.
+		 */
+		impl_ = std::make_unique<LscPolynomial>(sensorSize);
+		polynomial_ = true;
+		LOG(Lsc, Debug) << "Using polynomial Lsc";
+	} else {
+		LOG(Lsc, Error) << "Unsupported Lsc algorithm '"
+				<< type << "'";
+		return -EINVAL;
+	}
+
+	const ValueNode &yamlSets = tuningData["sets"];
+	if (!yamlSets.isList()) {
+		LOG(Lsc, Error) << "'sets' parameter not found in tuning file";
+		return -EINVAL;
+	}
+
+	int ret = impl_->parseLscData(yamlSets);
+	if (ret)
+		return ret;
+
+	controls[&controls::LensShadingCorrectionEnable] =
+		ControlInfo(false, true, true);
+
+	return 0;
+}
+
+/**
+ * \param[in] state The LSC active state
+ * \param[in] analogCrop The current sensor analog crop rectangle
+ * \param[in] xPos List of horizontal positions of the LSC grid nodes
+ * \param[in] yPos List of vertical positions of the LSC grid nodes
+ *
+ * Re-sample the LSC data for an \a analogCrop.
+ *
+ * LSC tables are generated at tuning time using a known sensor configuration.
+ * When a new streaming session is started, it might use a different sensor
+ * configuration for which the LSC tables need to be adjusted to.
+ *
+ * This function re-generates the LSC tables to adapt them to a new sensor
+ * configuration, specifically it re-samples the LSC data for a new \a
+ * analogCrop on a grid specified by \a xPos and \a yPos. Re-sampling of
+ * LSC data is currently supported by polynomial-based LSC tables.
+ *
+ * \sa LscImplementation::sampleForCrop
+ *
+ * \return 0 on success, a negative error code otherwise
+ */
+int LscAlgorithm::configure(lsc::ActiveState &state, const Rectangle &analogCrop,
+			    const std::vector<double> &xPos,
+			    const std::vector<double> &yPos)
+{
+	LOG(Lsc, Debug) << "Sample Lsc data for " << analogCrop;
+	lsc::ComponentsMap lscData =
+		impl_->sampleForCrop(analogCrop, xPos, yPos);
+
+	/*
+	 * Retain a copy of the components table.
+	 *
+	 * We could avoid a copy here if getComponents() could
+	 * return sets_.data() but I wasn't able to work around the
+	 * compiler refusing it.
+	 */
+	lscData_ = lscData;
+
+	sets_.setData(std::move(lscData));
+	state.enabled = true;
+
+	return 0;
+}
+
+/**
+ * \brief Queue a request to the lsc algorithm
+ * \param[in] state The lsc active state
+ * \param[in] context The lsc frame context
+ * \param[in] controls The list of controls associated with a Request
+ *
+ * Queue a new list of \a controls to the lsc algorithm.
+ * The only supported control is controls::LensShadingCorrectionEnable.
+ */
+void LscAlgorithm::queueRequest(lsc::ActiveState &state,
+				lsc::FrameContext &context,
+				const ControlList &controls)
+{
+	const auto &lscEnable = controls.get(controls::LensShadingCorrectionEnable);
+	if (lscEnable && *lscEnable != state.enabled) {
+		state.enabled = *lscEnable;
+
+		LOG(Lsc, Debug)
+			<< (state.enabled ? "Enabling" : "Disabling") << " Lsc";
+
+		context.update = true;
+	}
+
+	context.enabled = state.enabled;
+}
+
+/**
+ * \brief Populate the list of lsc metadata
+ * \param[in] context The lsc frame context
+ * \param[in] metadata The list of metadata
+ *
+ * Populates the list of \a metadata with controls handled by the LscAlgorithm
+ * class. The only supported metadata is controls::LensShadingCorrectionEnable.
+ */
+void LscAlgorithm::process(lsc::FrameContext &context, ControlList &metadata)
+{
+	metadata.set(controls::LensShadingCorrectionEnable, context.enabled);
+}
+
+/**
+ * \fn LscAlgorithm::interpolateComponents
+ * \brief Interpolate the LSC tables for a given colour temperature
+ * \param[in] ct The colour temperature
+ *
+ * LSC tables are generated using different colour temperatures during the
+ * tuning phase.
+ *
+ * This function returns the interpolated LSC data for a given \a ct
+ * colour temperature.
+ *
+ * IPA algorithm can use this function to obtain a list of gains per-colour
+ * component to program their LSC engines with every time a significant enough
+ * change in colour temperature is detected.
+ *
+ * Calling this function is only valid after LscAlgorithm::configure() has been
+ * called. An empty components list is returned otherwise.
+ *
+ * \return The LSC gains table interpolated for temperature \a ct
+ */
+
+/**
+ * \fn LscAlgorithm::getComponents
+ *
+ * Return the map of LSC data per colour temperature.
+ *
+ * Calling this function is only valid after LscAlgorithm::configure() has been
+ * called. An empty components list is returned otherwise.
+ *
+ * \return The map of LSC gains tables per colour-temperature
+ */
+
 } /* namespace ipa */
 
 } /* namespace libcamera */
diff --git a/src/ipa/libipa/lsc.h b/src/ipa/libipa/lsc.h
index 73519564feff..9a51d32c3464 100644
--- a/src/ipa/libipa/lsc.h
+++ b/src/ipa/libipa/lsc.h
@@ -7,6 +7,17 @@ 
 
 #pragma once
 
+#include <memory>
+#include <vector>
+
+#include <libcamera/controls.h>
+#include <libcamera/geometry.h>
+
+#include "libcamera/internal/value_node.h"
+
+#include "interpolator.h"
+#include "lsc_base.h"
+
 namespace libcamera {
 
 namespace ipa {
@@ -24,6 +35,37 @@  struct FrameContext {
 
 } /* namespace lsc */
 
+class LscAlgorithm
+{
+public:
+	int init(const ValueNode &tuningData, const Size &sensorSize,
+		 ControlInfoMap::Map &controls);
+
+	int configure(lsc::ActiveState &state, const Rectangle &analogCrop,
+		      const std::vector<double> &xPos,
+		      const std::vector<double> &yPos);
+
+	void queueRequest(lsc::ActiveState &state, lsc::FrameContext &context,
+			  const ControlList &controls);
+	void process(lsc::FrameContext &context, ControlList &metadata);
+
+	const lsc::Components interpolateComponents(unsigned int ct)
+	{
+		return sets_.getInterpolated(ct);
+	}
+
+	const lsc::ComponentsMap getComponents()
+	{
+		return lscData_;
+	}
+
+private:
+	std::unique_ptr<LscImplementation> impl_;
+	Interpolator<lsc::Components> sets_;
+	lsc::ComponentsMap lscData_;
+	bool polynomial_;
+};
+
 } /* namespace ipa */
 
 } /* namespace libcamera */