| Message ID | 20260706-libipa-algorithms-v3-16-968757b038bb@ideasonboard.com |
|---|---|
| State | Superseded |
| Headers | show |
| Series |
|
| Related | show |
Quoting Jacopo Mondi (2026-07-06 09:01:36) > Move the LscPolynomial class to libipa from RkISP1. > > Rename the class from LscPolynomialImpl to a simpler LscPolynomial. > The class is copied verbatim, only documntation has been added. s/documntation/documentation/ > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > --- > src/ipa/libipa/lsc_polynomial.cpp | 179 +++++++++++++++++++++++++++++++++++++- > src/ipa/libipa/lsc_polynomial.h | 46 ++++++++-- > src/ipa/rkisp1/algorithms/lsc.cpp | 162 +--------------------------------- > src/ipa/rkisp1/algorithms/lsc.h | 1 - > 4 files changed, 218 insertions(+), 170 deletions(-) > > diff --git a/src/ipa/libipa/lsc_polynomial.cpp b/src/ipa/libipa/lsc_polynomial.cpp > index a845d8b1783b..5c4ffc98797e 100644 > --- a/src/ipa/libipa/lsc_polynomial.cpp > +++ b/src/ipa/libipa/lsc_polynomial.cpp > @@ -2,11 +2,14 @@ > /* > * Copyright (C) 2024, Ideas On Board > * > - * Polynomial class to represent lens shading correction > + * Polynomial based lens shading correction > */ > > #include "lsc_polynomial.h" > > +#include <assert.h> > +#include <cmath> > + > #include <libcamera/base/log.h> > > /** > @@ -109,6 +112,180 @@ void Polynomial::setReferenceImageSize(const Size &size) > > } /* namespace lsc */ > > +/** > + * \class LscPolynomial > + * \brief Radial Polynomial lsc algorithm implementation > + * > + * Polynomial-based lsc algorithm implementation. The LscPolynomial class > + * implements lsc support using Polynomial to represent the shading artifacts 'using a Polynomial' > + * map. > + * > + * \sa LscImplementation > + */ > + > +/** > + * \fn LscPolynomial::LscPolynomial > + * \param[in] sensorSize The physical sensor size > + * > + * Construct an LscPolynomial > + */ > + > +/** > + * \brief Parse polynomial lsc data > + * \param[in] sets The tuning file content > + * > + * Parse the lsc data in polyomial form from the \a sets tuning data. > + * > + * \return 0 on success or a negative error number otherwise > + */ > +int LscPolynomial::parseLscData(const ValueNode &sets) > +{ > + for (const auto &set : sets.asList()) { > + std::optional<lsc::Polynomial> pr, pgr, pgb, pb; > + uint32_t ct = set["ct"].get<uint32_t>(0); > + > + if (lscData_.count(ct)) { > + LOG(LscPolynomial, Error) > + << "Multiple sets found for " > + << "color temperature " << ct; > + return -EINVAL; > + } > + > + pr = set["r"].get<lsc::Polynomial>(); > + pgr = set["gr"].get<lsc::Polynomial>(); > + pgb = set["gb"].get<lsc::Polynomial>(); > + pb = set["b"].get<lsc::Polynomial>(); > + > + if (!(pr || pgr || pgb || pb)) { > + LOG(LscPolynomial, Error) > + << "Failed to parse polynomial for " > + << "colour temperature " << ct; > + return -EINVAL; > + } > + > + pr->setReferenceImageSize(sensorSize_); > + pgr->setReferenceImageSize(sensorSize_); > + pgb->setReferenceImageSize(sensorSize_); > + pb->setReferenceImageSize(sensorSize_); > + > + lscData_.emplace(std::piecewise_construct, > + std::forward_as_tuple(ct), > + std::forward_as_tuple(PolynomialComponents{ *pr, *pgr, *pgb, *pb })); > + } > + > + if (lscData_.empty()) { > + LOG(LscPolynomial, Error) << "Failed to load any sets"; > + return -EINVAL; > + } > + > + return 0; > +} > + > +/** > + * \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. > + * > + * Polynomial Lsc tables can be re-sampled for a given sensor frame resolution > + * using a list of horizontal and vertical nodes that define the lsc grid on > + * which the polynomial is re-sampled on. > + * > + * \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. > + */ > +lsc::ComponentsMap > +LscPolynomial::sampleForCrop(const Rectangle &cropRectangle, > + Span<const double> xSizes, > + Span<const double> ySizes) > +{ > + std::vector<double> xPos = sizesListToPositions(xSizes); > + std::vector<double> yPos = sizesListToPositions(ySizes); > + > + lsc::ComponentsMap components; > + > + for (const auto &[k, p] : lscData_) { > + components[k] = { > + samplePolynomial(p.pr, xPos, yPos, cropRectangle), > + samplePolynomial(p.pgr, xPos, yPos, cropRectangle), > + samplePolynomial(p.pgb, xPos, yPos, cropRectangle), > + samplePolynomial(p.pb, xPos, yPos, cropRectangle) > + }; > + } > + > + return components; > +} > + > +std::vector<uint16_t> > +LscPolynomial::samplePolynomial(const lsc::Polynomial &poly, > + Span<const double> xPositions, > + Span<const double> yPositions, > + const Rectangle &cropRectangle) > +{ > + double m = poly.getM(); > + double x0 = cropRectangle.x / m; > + double y0 = cropRectangle.y / m; > + double w = cropRectangle.width / m; > + double h = cropRectangle.height / m; > + std::vector<uint16_t> samples; > + > + samples.reserve(xPositions.size() * yPositions.size()); > + > + for (double y : yPositions) { > + for (double x : xPositions) { > + double xp = x0 + x * w; > + double yp = y0 + y * h; > + /* > + * The hardware uses 2.10 fixed point format and limits > + * the legal values to [1..3.999]. Scale and clamp the > + * sampled value accordingly. > + */ > + int v = static_cast<int>( > + poly.sampleAtNormalizedPixelPos(xp, yp) * > + 1024); > + v = std::clamp(v, 1024, 4095); > + samples.push_back(v); I see 'hardware' specifics here, but I assume they'll move out in the refactoring steps next. > + } > + } > + return samples; > +} > + > +/* > + * The rkisp1 LSC grid spacing is defined by the cell sizes on the top-left Same here, but I'm going to accept that these will become generics in the series: Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > + * quadrant of the grid. This is then mirrored in hardware to the other > + * quadrants. See parseSizes() for further details. For easier handling, this > + * function converts the cell sizes of half the grid to a list of position of > + * the whole grid (on one axis). Example: > + * > + * input: | 0.2 | 0.3 | > + * output: 0.0 0.2 0.5 0.8 1.0 > + */ > +std::vector<double> > +LscPolynomial::sizesListToPositions(Span<const double> sizes) > +{ > + const int half = sizes.size(); > + std::vector<double> positions(half * 2 + 1); > + double x = 0.0; > + > + positions[half] = 0.5; > + for (int i = 1; i <= half; i++) { > + x += sizes[half - i]; > + positions[half - i] = 0.5 - x; > + positions[half + i] = 0.5 + x; > + } > + > + return positions; > +} > + > } /* namespace ipa */ > > #ifndef __DOXYGEN__ > diff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h > index 2caf46d2d759..17c2c34499f0 100644 > --- a/src/ipa/libipa/lsc_polynomial.h > +++ b/src/ipa/libipa/lsc_polynomial.h > @@ -2,25 +2,23 @@ > /* > * Copyright (C) 2024, Ideas On Board > * > - * Helper for radial polynomial used in lens shading correction. > + * Polynomial based lens shading correction > */ > #pragma once > > -#include <algorithm> > #include <array> > -#include <assert.h> > -#include <cmath> > +#include <map> > +#include <vector> > > -#include <libcamera/base/log.h> > #include <libcamera/base/span.h> > > #include <libcamera/geometry.h> > > #include "libcamera/internal/value_node.h" > > -namespace libcamera { > +#include "lsc_base.h" > > -LOG_DECLARE_CATEGORY(LscPolynomial) > +namespace libcamera { > > namespace ipa { > > @@ -52,6 +50,40 @@ private: > > } /* namespace lsc */ > > +class LscPolynomial : public LscImplementation > +{ > +private: > + struct PolynomialComponents { > + lsc::Polynomial pr; > + lsc::Polynomial pgr; > + lsc::Polynomial pgb; > + lsc::Polynomial pb; > + }; > + using PolynomialComponentsMap = std::map<unsigned int, PolynomialComponents>; > + > +public: > + LscPolynomial(const Size &sensorSize) > + : sensorSize_(sensorSize) > + { > + } > + > + int parseLscData(const ValueNode &sets) override; > + > + lsc::ComponentsMap > + sampleForCrop(const Rectangle &cropRectangle, > + Span<const double> xSizes, > + Span<const double> ySizes) override; > + > +private: > + std::vector<double> sizesListToPositions(Span<const double> sizes); > + std::vector<uint16_t> samplePolynomial(const lsc::Polynomial &poly, > + Span<const double> xPositions, > + Span<const double> yPositions, > + const Rectangle &cropRectangle); > + PolynomialComponentsMap lscData_; > + Size sensorSize_; > +}; > + > } /* namespace ipa */ > > } /* namespace libcamera */ > diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp > index 910b2ced292e..a4ea879aaa83 100644 > --- a/src/ipa/rkisp1/algorithms/lsc.cpp > +++ b/src/ipa/rkisp1/algorithms/lsc.cpp > @@ -33,166 +33,6 @@ namespace { > > constexpr int kColourTemperatureQuantization = 10; > > -class LscPolynomialImpl : public LscImplementation > -{ > -private: > - struct PolynomialComponents { > - lsc::Polynomial pr; > - lsc::Polynomial pgr; > - lsc::Polynomial pgb; > - lsc::Polynomial pb; > - }; > - using PolynomialComponentsMap = std::map<unsigned int, PolynomialComponents>; > - > -public: > - LscPolynomialImpl(const Size &sensorSize) > - : sensorSize_(sensorSize) > - { > - } > - > - int parseLscData(const ValueNode &sets) override; > - > - lsc::ComponentsMap > - sampleForCrop(const Rectangle &cropRectangle, > - Span<const double> xSizes, > - Span<const double> ySizes) override; > - > -private: > - std::vector<double> sizesListToPositions(Span<const double> sizes); > - std::vector<uint16_t> samplePolynomial(const lsc::Polynomial &poly, > - Span<const double> xPositions, > - Span<const double> yPositions, > - const Rectangle &cropRectangle); > - PolynomialComponentsMap lscData_; > - Size sensorSize_; > -}; > - > -int LscPolynomialImpl::parseLscData(const ValueNode &sets) > -{ > - for (const auto &set : sets.asList()) { > - std::optional<lsc::Polynomial> pr, pgr, pgb, pb; > - uint32_t ct = set["ct"].get<uint32_t>(0); > - > - if (lscData_.count(ct)) { > - LOG(RkISP1Lsc, Error) > - << "Multiple sets found for " > - << "color temperature " << ct; > - return -EINVAL; > - } > - > - pr = set["r"].get<lsc::Polynomial>(); > - pgr = set["gr"].get<lsc::Polynomial>(); > - pgb = set["gb"].get<lsc::Polynomial>(); > - pb = set["b"].get<lsc::Polynomial>(); > - > - if (!(pr || pgr || pgb || pb)) { > - LOG(RkISP1Lsc, Error) > - << "Failed to parse polynomial for " > - << "colour temperature " << ct; > - return -EINVAL; > - } > - > - pr->setReferenceImageSize(sensorSize_); > - pgr->setReferenceImageSize(sensorSize_); > - pgb->setReferenceImageSize(sensorSize_); > - pb->setReferenceImageSize(sensorSize_); > - > - lscData_.emplace(std::piecewise_construct, > - std::forward_as_tuple(ct), > - std::forward_as_tuple(PolynomialComponents{ *pr, *pgr, *pgb, *pb })); > - } > - > - if (lscData_.empty()) { > - LOG(RkISP1Lsc, Error) << "Failed to load any sets"; > - return -EINVAL; > - } > - > - return 0; > -} > - > -lsc::ComponentsMap > -LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle, > - Span<const double> xSizes, > - Span<const double> ySizes) > -{ > - std::vector<double> xPos = sizesListToPositions(xSizes); > - std::vector<double> yPos = sizesListToPositions(ySizes); > - > - lsc::ComponentsMap components; > - > - for (const auto &[k, p] : lscData_) { > - components[k] = { > - samplePolynomial(p.pr, xPos, yPos, cropRectangle), > - samplePolynomial(p.pgr, xPos, yPos, cropRectangle), > - samplePolynomial(p.pgb, xPos, yPos, cropRectangle), > - samplePolynomial(p.pb, xPos, yPos, cropRectangle) > - }; > - } > - > - return components; > -} > - > -std::vector<uint16_t> > -LscPolynomialImpl::samplePolynomial(const lsc::Polynomial &poly, > - Span<const double> xPositions, > - Span<const double> yPositions, > - const Rectangle &cropRectangle) > -{ > - double m = poly.getM(); > - double x0 = cropRectangle.x / m; > - double y0 = cropRectangle.y / m; > - double w = cropRectangle.width / m; > - double h = cropRectangle.height / m; > - std::vector<uint16_t> samples; > - > - samples.reserve(xPositions.size() * yPositions.size()); > - > - for (double y : yPositions) { > - for (double x : xPositions) { > - double xp = x0 + x * w; > - double yp = y0 + y * h; > - /* > - * The hardware uses 2.10 fixed point format and limits > - * the legal values to [1..3.999]. Scale and clamp the > - * sampled value accordingly. > - */ > - int v = static_cast<int>( > - poly.sampleAtNormalizedPixelPos(xp, yp) * > - 1024); > - v = std::clamp(v, 1024, 4095); > - samples.push_back(v); > - } > - } > - return samples; > -} > - > -/* > - * The rkisp1 LSC grid spacing is defined by the cell sizes on the top-left > - * quadrant of the grid. This is then mirrored in hardware to the other > - * quadrants. See parseSizes() for further details. For easier handling, this > - * function converts the cell sizes of half the grid to a list of position of > - * the whole grid (on one axis). Example: > - * > - * input: | 0.2 | 0.3 | > - * output: 0.0 0.2 0.5 0.8 1.0 > - */ > -std::vector<double> > -LscPolynomialImpl::sizesListToPositions(Span<const double> sizes) > -{ > - const int half = sizes.size(); > - std::vector<double> positions(half * 2 + 1); > - double x = 0.0; > - > - positions[half] = 0.5; > - for (int i = 1; i <= half; i++) { > - x += sizes[half - i]; > - positions[half - i] = 0.5 - x; > - positions[half + i] = 0.5 + x; > - } > - > - return positions; > -} > - > class LscTableImpl : public LscImplementation > { > public: > @@ -358,7 +198,7 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, > * \todo: Most likely the reference frame should be native_size. > * Let's wait how the internal discussions progress. > */ > - algo_ = std::make_unique<LscPolynomialImpl>(context.sensorInfo.activeAreaSize); > + algo_ = std::make_unique<LscPolynomial>(context.sensorInfo.activeAreaSize); > ret = algo_->parseLscData(sets); > } else { > LOG(RkISP1Lsc, Error) << "Unsupported LSC data type '" > diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h > index b21c91c0d81f..2a428293cb2e 100644 > --- a/src/ipa/rkisp1/algorithms/lsc.h > +++ b/src/ipa/rkisp1/algorithms/lsc.h > @@ -7,7 +7,6 @@ > > #pragma once > > -#include <map> > #include <memory> > > #include "libipa/interpolator.h" > > -- > 2.54.0 >
diff --git a/src/ipa/libipa/lsc_polynomial.cpp b/src/ipa/libipa/lsc_polynomial.cpp index a845d8b1783b..5c4ffc98797e 100644 --- a/src/ipa/libipa/lsc_polynomial.cpp +++ b/src/ipa/libipa/lsc_polynomial.cpp @@ -2,11 +2,14 @@ /* * Copyright (C) 2024, Ideas On Board * - * Polynomial class to represent lens shading correction + * Polynomial based lens shading correction */ #include "lsc_polynomial.h" +#include <assert.h> +#include <cmath> + #include <libcamera/base/log.h> /** @@ -109,6 +112,180 @@ void Polynomial::setReferenceImageSize(const Size &size) } /* namespace lsc */ +/** + * \class LscPolynomial + * \brief Radial Polynomial lsc algorithm implementation + * + * Polynomial-based lsc algorithm implementation. The LscPolynomial class + * implements lsc support using Polynomial to represent the shading artifacts + * map. + * + * \sa LscImplementation + */ + +/** + * \fn LscPolynomial::LscPolynomial + * \param[in] sensorSize The physical sensor size + * + * Construct an LscPolynomial + */ + +/** + * \brief Parse polynomial lsc data + * \param[in] sets The tuning file content + * + * Parse the lsc data in polyomial form from the \a sets tuning data. + * + * \return 0 on success or a negative error number otherwise + */ +int LscPolynomial::parseLscData(const ValueNode &sets) +{ + for (const auto &set : sets.asList()) { + std::optional<lsc::Polynomial> pr, pgr, pgb, pb; + uint32_t ct = set["ct"].get<uint32_t>(0); + + if (lscData_.count(ct)) { + LOG(LscPolynomial, Error) + << "Multiple sets found for " + << "color temperature " << ct; + return -EINVAL; + } + + pr = set["r"].get<lsc::Polynomial>(); + pgr = set["gr"].get<lsc::Polynomial>(); + pgb = set["gb"].get<lsc::Polynomial>(); + pb = set["b"].get<lsc::Polynomial>(); + + if (!(pr || pgr || pgb || pb)) { + LOG(LscPolynomial, Error) + << "Failed to parse polynomial for " + << "colour temperature " << ct; + return -EINVAL; + } + + pr->setReferenceImageSize(sensorSize_); + pgr->setReferenceImageSize(sensorSize_); + pgb->setReferenceImageSize(sensorSize_); + pb->setReferenceImageSize(sensorSize_); + + lscData_.emplace(std::piecewise_construct, + std::forward_as_tuple(ct), + std::forward_as_tuple(PolynomialComponents{ *pr, *pgr, *pgb, *pb })); + } + + if (lscData_.empty()) { + LOG(LscPolynomial, Error) << "Failed to load any sets"; + return -EINVAL; + } + + return 0; +} + +/** + * \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. + * + * Polynomial Lsc tables can be re-sampled for a given sensor frame resolution + * using a list of horizontal and vertical nodes that define the lsc grid on + * which the polynomial is re-sampled on. + * + * \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. + */ +lsc::ComponentsMap +LscPolynomial::sampleForCrop(const Rectangle &cropRectangle, + Span<const double> xSizes, + Span<const double> ySizes) +{ + std::vector<double> xPos = sizesListToPositions(xSizes); + std::vector<double> yPos = sizesListToPositions(ySizes); + + lsc::ComponentsMap components; + + for (const auto &[k, p] : lscData_) { + components[k] = { + samplePolynomial(p.pr, xPos, yPos, cropRectangle), + samplePolynomial(p.pgr, xPos, yPos, cropRectangle), + samplePolynomial(p.pgb, xPos, yPos, cropRectangle), + samplePolynomial(p.pb, xPos, yPos, cropRectangle) + }; + } + + return components; +} + +std::vector<uint16_t> +LscPolynomial::samplePolynomial(const lsc::Polynomial &poly, + Span<const double> xPositions, + Span<const double> yPositions, + const Rectangle &cropRectangle) +{ + double m = poly.getM(); + double x0 = cropRectangle.x / m; + double y0 = cropRectangle.y / m; + double w = cropRectangle.width / m; + double h = cropRectangle.height / m; + std::vector<uint16_t> samples; + + samples.reserve(xPositions.size() * yPositions.size()); + + for (double y : yPositions) { + for (double x : xPositions) { + double xp = x0 + x * w; + double yp = y0 + y * h; + /* + * The hardware uses 2.10 fixed point format and limits + * the legal values to [1..3.999]. Scale and clamp the + * sampled value accordingly. + */ + int v = static_cast<int>( + poly.sampleAtNormalizedPixelPos(xp, yp) * + 1024); + v = std::clamp(v, 1024, 4095); + samples.push_back(v); + } + } + return samples; +} + +/* + * The rkisp1 LSC grid spacing is defined by the cell sizes on the top-left + * quadrant of the grid. This is then mirrored in hardware to the other + * quadrants. See parseSizes() for further details. For easier handling, this + * function converts the cell sizes of half the grid to a list of position of + * the whole grid (on one axis). Example: + * + * input: | 0.2 | 0.3 | + * output: 0.0 0.2 0.5 0.8 1.0 + */ +std::vector<double> +LscPolynomial::sizesListToPositions(Span<const double> sizes) +{ + const int half = sizes.size(); + std::vector<double> positions(half * 2 + 1); + double x = 0.0; + + positions[half] = 0.5; + for (int i = 1; i <= half; i++) { + x += sizes[half - i]; + positions[half - i] = 0.5 - x; + positions[half + i] = 0.5 + x; + } + + return positions; +} + } /* namespace ipa */ #ifndef __DOXYGEN__ diff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h index 2caf46d2d759..17c2c34499f0 100644 --- a/src/ipa/libipa/lsc_polynomial.h +++ b/src/ipa/libipa/lsc_polynomial.h @@ -2,25 +2,23 @@ /* * Copyright (C) 2024, Ideas On Board * - * Helper for radial polynomial used in lens shading correction. + * Polynomial based lens shading correction */ #pragma once -#include <algorithm> #include <array> -#include <assert.h> -#include <cmath> +#include <map> +#include <vector> -#include <libcamera/base/log.h> #include <libcamera/base/span.h> #include <libcamera/geometry.h> #include "libcamera/internal/value_node.h" -namespace libcamera { +#include "lsc_base.h" -LOG_DECLARE_CATEGORY(LscPolynomial) +namespace libcamera { namespace ipa { @@ -52,6 +50,40 @@ private: } /* namespace lsc */ +class LscPolynomial : public LscImplementation +{ +private: + struct PolynomialComponents { + lsc::Polynomial pr; + lsc::Polynomial pgr; + lsc::Polynomial pgb; + lsc::Polynomial pb; + }; + using PolynomialComponentsMap = std::map<unsigned int, PolynomialComponents>; + +public: + LscPolynomial(const Size &sensorSize) + : sensorSize_(sensorSize) + { + } + + int parseLscData(const ValueNode &sets) override; + + lsc::ComponentsMap + sampleForCrop(const Rectangle &cropRectangle, + Span<const double> xSizes, + Span<const double> ySizes) override; + +private: + std::vector<double> sizesListToPositions(Span<const double> sizes); + std::vector<uint16_t> samplePolynomial(const lsc::Polynomial &poly, + Span<const double> xPositions, + Span<const double> yPositions, + const Rectangle &cropRectangle); + PolynomialComponentsMap lscData_; + Size sensorSize_; +}; + } /* namespace ipa */ } /* namespace libcamera */ diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 910b2ced292e..a4ea879aaa83 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -33,166 +33,6 @@ namespace { constexpr int kColourTemperatureQuantization = 10; -class LscPolynomialImpl : public LscImplementation -{ -private: - struct PolynomialComponents { - lsc::Polynomial pr; - lsc::Polynomial pgr; - lsc::Polynomial pgb; - lsc::Polynomial pb; - }; - using PolynomialComponentsMap = std::map<unsigned int, PolynomialComponents>; - -public: - LscPolynomialImpl(const Size &sensorSize) - : sensorSize_(sensorSize) - { - } - - int parseLscData(const ValueNode &sets) override; - - lsc::ComponentsMap - sampleForCrop(const Rectangle &cropRectangle, - Span<const double> xSizes, - Span<const double> ySizes) override; - -private: - std::vector<double> sizesListToPositions(Span<const double> sizes); - std::vector<uint16_t> samplePolynomial(const lsc::Polynomial &poly, - Span<const double> xPositions, - Span<const double> yPositions, - const Rectangle &cropRectangle); - PolynomialComponentsMap lscData_; - Size sensorSize_; -}; - -int LscPolynomialImpl::parseLscData(const ValueNode &sets) -{ - for (const auto &set : sets.asList()) { - std::optional<lsc::Polynomial> pr, pgr, pgb, pb; - uint32_t ct = set["ct"].get<uint32_t>(0); - - if (lscData_.count(ct)) { - LOG(RkISP1Lsc, Error) - << "Multiple sets found for " - << "color temperature " << ct; - return -EINVAL; - } - - pr = set["r"].get<lsc::Polynomial>(); - pgr = set["gr"].get<lsc::Polynomial>(); - pgb = set["gb"].get<lsc::Polynomial>(); - pb = set["b"].get<lsc::Polynomial>(); - - if (!(pr || pgr || pgb || pb)) { - LOG(RkISP1Lsc, Error) - << "Failed to parse polynomial for " - << "colour temperature " << ct; - return -EINVAL; - } - - pr->setReferenceImageSize(sensorSize_); - pgr->setReferenceImageSize(sensorSize_); - pgb->setReferenceImageSize(sensorSize_); - pb->setReferenceImageSize(sensorSize_); - - lscData_.emplace(std::piecewise_construct, - std::forward_as_tuple(ct), - std::forward_as_tuple(PolynomialComponents{ *pr, *pgr, *pgb, *pb })); - } - - if (lscData_.empty()) { - LOG(RkISP1Lsc, Error) << "Failed to load any sets"; - return -EINVAL; - } - - return 0; -} - -lsc::ComponentsMap -LscPolynomialImpl::sampleForCrop(const Rectangle &cropRectangle, - Span<const double> xSizes, - Span<const double> ySizes) -{ - std::vector<double> xPos = sizesListToPositions(xSizes); - std::vector<double> yPos = sizesListToPositions(ySizes); - - lsc::ComponentsMap components; - - for (const auto &[k, p] : lscData_) { - components[k] = { - samplePolynomial(p.pr, xPos, yPos, cropRectangle), - samplePolynomial(p.pgr, xPos, yPos, cropRectangle), - samplePolynomial(p.pgb, xPos, yPos, cropRectangle), - samplePolynomial(p.pb, xPos, yPos, cropRectangle) - }; - } - - return components; -} - -std::vector<uint16_t> -LscPolynomialImpl::samplePolynomial(const lsc::Polynomial &poly, - Span<const double> xPositions, - Span<const double> yPositions, - const Rectangle &cropRectangle) -{ - double m = poly.getM(); - double x0 = cropRectangle.x / m; - double y0 = cropRectangle.y / m; - double w = cropRectangle.width / m; - double h = cropRectangle.height / m; - std::vector<uint16_t> samples; - - samples.reserve(xPositions.size() * yPositions.size()); - - for (double y : yPositions) { - for (double x : xPositions) { - double xp = x0 + x * w; - double yp = y0 + y * h; - /* - * The hardware uses 2.10 fixed point format and limits - * the legal values to [1..3.999]. Scale and clamp the - * sampled value accordingly. - */ - int v = static_cast<int>( - poly.sampleAtNormalizedPixelPos(xp, yp) * - 1024); - v = std::clamp(v, 1024, 4095); - samples.push_back(v); - } - } - return samples; -} - -/* - * The rkisp1 LSC grid spacing is defined by the cell sizes on the top-left - * quadrant of the grid. This is then mirrored in hardware to the other - * quadrants. See parseSizes() for further details. For easier handling, this - * function converts the cell sizes of half the grid to a list of position of - * the whole grid (on one axis). Example: - * - * input: | 0.2 | 0.3 | - * output: 0.0 0.2 0.5 0.8 1.0 - */ -std::vector<double> -LscPolynomialImpl::sizesListToPositions(Span<const double> sizes) -{ - const int half = sizes.size(); - std::vector<double> positions(half * 2 + 1); - double x = 0.0; - - positions[half] = 0.5; - for (int i = 1; i <= half; i++) { - x += sizes[half - i]; - positions[half - i] = 0.5 - x; - positions[half + i] = 0.5 + x; - } - - return positions; -} - class LscTableImpl : public LscImplementation { public: @@ -358,7 +198,7 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, * \todo: Most likely the reference frame should be native_size. * Let's wait how the internal discussions progress. */ - algo_ = std::make_unique<LscPolynomialImpl>(context.sensorInfo.activeAreaSize); + algo_ = std::make_unique<LscPolynomial>(context.sensorInfo.activeAreaSize); ret = algo_->parseLscData(sets); } else { LOG(RkISP1Lsc, Error) << "Unsupported LSC data type '" diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h index b21c91c0d81f..2a428293cb2e 100644 --- a/src/ipa/rkisp1/algorithms/lsc.h +++ b/src/ipa/rkisp1/algorithms/lsc.h @@ -7,7 +7,6 @@ #pragma once -#include <map> #include <memory> #include "libipa/interpolator.h"
Move the LscPolynomial class to libipa from RkISP1. Rename the class from LscPolynomialImpl to a simpler LscPolynomial. The class is copied verbatim, only documntation has been added. Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> --- src/ipa/libipa/lsc_polynomial.cpp | 179 +++++++++++++++++++++++++++++++++++++- src/ipa/libipa/lsc_polynomial.h | 46 ++++++++-- src/ipa/rkisp1/algorithms/lsc.cpp | 162 +--------------------------------- src/ipa/rkisp1/algorithms/lsc.h | 1 - 4 files changed, 218 insertions(+), 170 deletions(-)