| Message ID | 20260120-sklug-lsc-resampling-v2-dev-v5-13-ef5cec7b299f@ideasonboard.com |
|---|---|
| State | Superseded |
| Headers | show |
| Series |
|
| Related | show |
On Tue, Jan 20, 2026 at 01:26:18PM +0100, Stefan Klug wrote: > The lens shading correction is always applied based on the sensor crop > bounds. This leads to incorrect lens shading correction for analog crops > that do not cover the whole sensor. > > To fix that, we need to adapt the lens shading table for the selected > analog crop at configure time. Introduce an abstract ShadingDescriptor > class that holds the lens shading information that can then be sampled > at configure time for a specific crop rectangle. > > Resampling for a specific crop is only implemented for polynomial lsc > data. For tabular data, a warning is logged and the unmodified table is > returned. This matches the current functionality for tabular data and is > a huge improvement for polynomial data. > > Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> > > --- > > Changes in v4: > - Removed trailing dot from commit message > - Added missing 'override' > - Collected tags > > Changes in v2: > - Replaced "auto const" by "const auto" > - Replaces some vector parameters by Spans > - Changed sampleForCrop to return the components > - Replaced min/max by clamp > - Replaced map.swap() by move assignment > --- > src/ipa/rkisp1/algorithms/lsc.cpp | 233 ++++++++++++++++++++++++-------------- > src/ipa/rkisp1/algorithms/lsc.h | 13 +++ > 2 files changed, 159 insertions(+), 87 deletions(-) > > diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp > index f51c690c2020c8a046fbab8f1da31b9ba4a32ac0..8589243ea04f5a712fb2ddd95677a197566f390f 100644 > --- a/src/ipa/rkisp1/algorithms/lsc.cpp > +++ b/src/ipa/rkisp1/algorithms/lsc.cpp > @@ -72,38 +72,127 @@ namespace { > > constexpr int kColourTemperatureQuantization = 10; > > -class LscPolynomialLoader > +class LscPolynomialShadingDescriptor : public LensShadingCorrection::ShadingDescriptor > { > public: > - LscPolynomialLoader(const Size &sensorSize, > - const Rectangle &cropRectangle, > - const std::vector<double> &xSizes, > - const std::vector<double> &ySizes) > - : sensorSize_(sensorSize), > - cropRectangle_(cropRectangle), > - xSizes_(xSizes), > - ySizes_(ySizes) > + LscPolynomialShadingDescriptor(const LscPolynomial &pr, const LscPolynomial &pgr, > + const LscPolynomial &pgb, const LscPolynomial &pb) > + : pr_(pr), pgr_(pgr), pgb_(pgb), pb_(pb) > { > } > > - int parseLscData(const YamlObject &yamlSets, > - std::map<unsigned int, LensShadingCorrection::Components> &lscData); > + LensShadingCorrection::Components sampleForCrop(const Rectangle &cropRectangle, > + Span<const double> xSizes, > + Span<const double> ySizes) override; > > private: > - std::vector<double> sizesListToPositions(const std::vector<double> &sizes); > std::vector<uint16_t> samplePolynomial(const LscPolynomial &poly, > Span<const double> xPositions, > Span<const double> yPositions, > const Rectangle &cropRectangle); > > + std::vector<double> sizesListToPositions(Span<const double> sizes); > + > + LscPolynomial pr_; > + LscPolynomial pgr_; > + LscPolynomial pgb_; > + LscPolynomial pb_; > +}; > + > +LensShadingCorrection::Components > +LscPolynomialShadingDescriptor::sampleForCrop(const Rectangle &cropRectangle, > + Span<const double> xSizes, > + Span<const double> ySizes) > +{ > + std::vector<double> xPos = sizesListToPositions(xSizes); > + std::vector<double> yPos = sizesListToPositions(ySizes); > + > + return { > + .r = samplePolynomial(pr_, xPos, yPos, cropRectangle), > + .gr = samplePolynomial(pgr_, xPos, yPos, cropRectangle), > + .gb = samplePolynomial(pgb_, xPos, yPos, cropRectangle), > + .b = samplePolynomial(pb_, xPos, yPos, cropRectangle) > + }; > +} > + > +std::vector<uint16_t> > +LscPolynomialShadingDescriptor::samplePolynomial(const LscPolynomial &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 first half of > + * the grid. This is then mirrored in hardware to the other half. See > + * parseSizes() for further details. For easier handling, this function converts Same comment here as in patch 04/15. > + * 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> > +LscPolynomialShadingDescriptor::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 LscPolynomialLoader > +{ > +public: > + LscPolynomialLoader(const Size &sensorSize) > + : sensorSize_(sensorSize) > + { > + } > + > + int parseLscData(const YamlObject &yamlSets, > + LensShadingCorrection::ShadingDescriptorMap &lscData); > + > +private: > Size sensorSize_; > - Rectangle cropRectangle_; > - const std::vector<double> &xSizes_; > - const std::vector<double> &ySizes_; > }; > > int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, > - std::map<unsigned int, LensShadingCorrection::Components> &lscData) > + LensShadingCorrection::ShadingDescriptorMap &lscData) > { > const auto &sets = yamlSets.asList(); > for (const auto &yamlSet : sets) { > @@ -117,7 +206,6 @@ int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, > return -EINVAL; > } > > - LensShadingCorrection::Components &set = lscData[ct]; > pr = yamlSet["r"].get<LscPolynomial>(); > pgr = yamlSet["gr"].get<LscPolynomial>(); > pgb = yamlSet["gb"].get<LscPolynomial>(); > @@ -135,12 +223,9 @@ int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, > pgb->setReferenceImageSize(sensorSize_); > pb->setReferenceImageSize(sensorSize_); > > - std::vector<double> xPos = sizesListToPositions(xSizes_); > - std::vector<double> yPos = sizesListToPositions(ySizes_); > - set.r = samplePolynomial(*pr, xPos, yPos, cropRectangle_); > - set.gr = samplePolynomial(*pgr, xPos, yPos, cropRectangle_); > - set.gb = samplePolynomial(*pgb, xPos, yPos, cropRectangle_); > - set.b = samplePolynomial(*pb, xPos, yPos, cropRectangle_); > + lscData.emplace( > + ct, std::make_unique<LscPolynomialShadingDescriptor>( > + *pr, *pgr, *pgb, *pb)); > } > > if (lscData.empty()) { > @@ -151,70 +236,33 @@ int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, > return 0; > } > > -/* > - * The rkisp1 LSC grid spacing is defined by the cell sizes on the first half of > - * the grid. This is then mirrored in hardware to the other half. 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> LscPolynomialLoader::sizesListToPositions(const std::vector<double> &sizes) > +class LscTableShadingDescriptor : public LensShadingCorrection::ShadingDescriptor > { > - 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; > +public: > + LscTableShadingDescriptor(LensShadingCorrection::Components components) > + : lscData_(std::move(components)) > + { > } > > - return positions; > -} > - > -std::vector<uint16_t> LscPolynomialLoader::samplePolynomial(const LscPolynomial &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::min(std::max(v, 1024), 4095); > - samples.push_back(v); > - } > + LensShadingCorrection::Components > + sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle, > + [[maybe_unused]] Span<const double> xSizes, > + [[maybe_unused]] Span<const double> ySizes) override > + { > + LOG(RkISP1Lsc, Warning) > + << "Tabular LSC data doesn't support resampling"; > + return lscData_; > } > - return samples; > -} > + > +private: > + LensShadingCorrection::Components lscData_; > +}; > > class LscTableLoader > { > public: > int parseLscData(const YamlObject &yamlSets, > - std::map<unsigned int, LensShadingCorrection::Components> &lscData); > + LensShadingCorrection::ShadingDescriptorMap &lscData); > > private: > std::vector<uint16_t> parseTable(const YamlObject &tuningData, > @@ -222,7 +270,7 @@ private: > }; > > int LscTableLoader::parseLscData(const YamlObject &yamlSets, > - std::map<unsigned int, LensShadingCorrection::Components> &lscData) > + LensShadingCorrection::ShadingDescriptorMap &lscData) > { > const auto &sets = yamlSets.asList(); > > @@ -236,8 +284,7 @@ int LscTableLoader::parseLscData(const YamlObject &yamlSets, > return -EINVAL; > } > > - LensShadingCorrection::Components &set = lscData[ct]; > - > + LensShadingCorrection::Components set; > set.r = parseTable(yamlSet, "r"); > set.gr = parseTable(yamlSet, "gr"); > set.gb = parseTable(yamlSet, "gb"); > @@ -250,6 +297,9 @@ int LscTableLoader::parseLscData(const YamlObject &yamlSets, > << " is missing tables"; > return -EINVAL; > } > + > + lscData.emplace( > + ct, std::make_unique<LscTableShadingDescriptor>(std::move(set))); > } > > if (lscData.empty()) { > @@ -341,7 +391,7 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, > return -EINVAL; > } > > - std::map<unsigned int, Components> lscData; > + ShadingDescriptorMap lscData; > int ret = 0; > > std::string type = tuningData["type"].get<std::string>("table"); > @@ -351,10 +401,11 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, > ret = loader.parseLscData(yamlSets, lscData); > } else if (type == "polynomial") { > LOG(RkISP1Lsc, Debug) << "Loading polynomial LSC data."; > - auto loader = LscPolynomialLoader(context.sensorInfo.activeAreaSize, > - context.sensorInfo.analogCrop, > - xSize_, > - ySize_); > + /* > + * \todo: Most likely the reference frame should be native_size. > + * Let's wait how the internal discussions progress. > + */ > + auto loader = LscPolynomialLoader(context.sensorInfo.activeAreaSize); > ret = loader.parseLscData(yamlSets, lscData); > } else { > LOG(RkISP1Lsc, Error) << "Unsupported LSC data type '" > @@ -365,7 +416,7 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, > if (ret) > return ret; > > - sets_.setData(std::move(lscData)); > + shadingDescriptors_ = std::move(lscData); > > return 0; > } > @@ -401,6 +452,14 @@ int LensShadingCorrection::configure(IPAContext &context, > yGrad_[i] = std::round(32768 / ySizes_[i]); > } > > + LOG(RkISP1Lsc, Debug) << "Sample LSC data for " << configInfo.analogCrop; > + std::map<unsigned int, LensShadingCorrection::Components> shadingData; > + for (const auto &[t, descriptor] : shadingDescriptors_) > + shadingData[t] = descriptor->sampleForCrop(configInfo.analogCrop, > + xSize_, ySize_); > + > + sets_.setData(std::move(shadingData)); > + > context.configuration.lsc.enabled = true; > return 0; > } > diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h > index 7b68dda1a0d4257c345e0f1b77aa498f8183c92f..3097740a6cb2ce9063a4ba087856987a489b0ab6 100644 > --- a/src/ipa/rkisp1/algorithms/lsc.h > +++ b/src/ipa/rkisp1/algorithms/lsc.h > @@ -8,6 +8,7 @@ > #pragma once > > #include <map> > +#include <memory> > > #include "libipa/interpolator.h" > > @@ -36,10 +37,22 @@ public: > std::vector<uint16_t> b; > }; > > + class ShadingDescriptor > + { > + public: > + virtual ~ShadingDescriptor() = default; > + virtual Components sampleForCrop(const Rectangle &cropRectangle, > + Span<const double> xSizes, > + Span<const double> ySizes) = 0; > + }; > + > + using ShadingDescriptorMap = std::map<unsigned int, std::unique_ptr<ShadingDescriptor>>; > + > private: > void setParameters(rkisp1_cif_isp_lsc_config &config); > void copyTable(rkisp1_cif_isp_lsc_config &config, const Components &set0); > > + ShadingDescriptorMap shadingDescriptors_; > ipa::Interpolator<Components> sets_; > std::vector<double> xSize_; > std::vector<double> ySize_;
diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index f51c690c2020c8a046fbab8f1da31b9ba4a32ac0..8589243ea04f5a712fb2ddd95677a197566f390f 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -72,38 +72,127 @@ namespace { constexpr int kColourTemperatureQuantization = 10; -class LscPolynomialLoader +class LscPolynomialShadingDescriptor : public LensShadingCorrection::ShadingDescriptor { public: - LscPolynomialLoader(const Size &sensorSize, - const Rectangle &cropRectangle, - const std::vector<double> &xSizes, - const std::vector<double> &ySizes) - : sensorSize_(sensorSize), - cropRectangle_(cropRectangle), - xSizes_(xSizes), - ySizes_(ySizes) + LscPolynomialShadingDescriptor(const LscPolynomial &pr, const LscPolynomial &pgr, + const LscPolynomial &pgb, const LscPolynomial &pb) + : pr_(pr), pgr_(pgr), pgb_(pgb), pb_(pb) { } - int parseLscData(const YamlObject &yamlSets, - std::map<unsigned int, LensShadingCorrection::Components> &lscData); + LensShadingCorrection::Components sampleForCrop(const Rectangle &cropRectangle, + Span<const double> xSizes, + Span<const double> ySizes) override; private: - std::vector<double> sizesListToPositions(const std::vector<double> &sizes); std::vector<uint16_t> samplePolynomial(const LscPolynomial &poly, Span<const double> xPositions, Span<const double> yPositions, const Rectangle &cropRectangle); + std::vector<double> sizesListToPositions(Span<const double> sizes); + + LscPolynomial pr_; + LscPolynomial pgr_; + LscPolynomial pgb_; + LscPolynomial pb_; +}; + +LensShadingCorrection::Components +LscPolynomialShadingDescriptor::sampleForCrop(const Rectangle &cropRectangle, + Span<const double> xSizes, + Span<const double> ySizes) +{ + std::vector<double> xPos = sizesListToPositions(xSizes); + std::vector<double> yPos = sizesListToPositions(ySizes); + + return { + .r = samplePolynomial(pr_, xPos, yPos, cropRectangle), + .gr = samplePolynomial(pgr_, xPos, yPos, cropRectangle), + .gb = samplePolynomial(pgb_, xPos, yPos, cropRectangle), + .b = samplePolynomial(pb_, xPos, yPos, cropRectangle) + }; +} + +std::vector<uint16_t> +LscPolynomialShadingDescriptor::samplePolynomial(const LscPolynomial &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 first half of + * the grid. This is then mirrored in hardware to the other half. 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> +LscPolynomialShadingDescriptor::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 LscPolynomialLoader +{ +public: + LscPolynomialLoader(const Size &sensorSize) + : sensorSize_(sensorSize) + { + } + + int parseLscData(const YamlObject &yamlSets, + LensShadingCorrection::ShadingDescriptorMap &lscData); + +private: Size sensorSize_; - Rectangle cropRectangle_; - const std::vector<double> &xSizes_; - const std::vector<double> &ySizes_; }; int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, - std::map<unsigned int, LensShadingCorrection::Components> &lscData) + LensShadingCorrection::ShadingDescriptorMap &lscData) { const auto &sets = yamlSets.asList(); for (const auto &yamlSet : sets) { @@ -117,7 +206,6 @@ int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, return -EINVAL; } - LensShadingCorrection::Components &set = lscData[ct]; pr = yamlSet["r"].get<LscPolynomial>(); pgr = yamlSet["gr"].get<LscPolynomial>(); pgb = yamlSet["gb"].get<LscPolynomial>(); @@ -135,12 +223,9 @@ int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, pgb->setReferenceImageSize(sensorSize_); pb->setReferenceImageSize(sensorSize_); - std::vector<double> xPos = sizesListToPositions(xSizes_); - std::vector<double> yPos = sizesListToPositions(ySizes_); - set.r = samplePolynomial(*pr, xPos, yPos, cropRectangle_); - set.gr = samplePolynomial(*pgr, xPos, yPos, cropRectangle_); - set.gb = samplePolynomial(*pgb, xPos, yPos, cropRectangle_); - set.b = samplePolynomial(*pb, xPos, yPos, cropRectangle_); + lscData.emplace( + ct, std::make_unique<LscPolynomialShadingDescriptor>( + *pr, *pgr, *pgb, *pb)); } if (lscData.empty()) { @@ -151,70 +236,33 @@ int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, return 0; } -/* - * The rkisp1 LSC grid spacing is defined by the cell sizes on the first half of - * the grid. This is then mirrored in hardware to the other half. 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> LscPolynomialLoader::sizesListToPositions(const std::vector<double> &sizes) +class LscTableShadingDescriptor : public LensShadingCorrection::ShadingDescriptor { - 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; +public: + LscTableShadingDescriptor(LensShadingCorrection::Components components) + : lscData_(std::move(components)) + { } - return positions; -} - -std::vector<uint16_t> LscPolynomialLoader::samplePolynomial(const LscPolynomial &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::min(std::max(v, 1024), 4095); - samples.push_back(v); - } + LensShadingCorrection::Components + sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle, + [[maybe_unused]] Span<const double> xSizes, + [[maybe_unused]] Span<const double> ySizes) override + { + LOG(RkISP1Lsc, Warning) + << "Tabular LSC data doesn't support resampling"; + return lscData_; } - return samples; -} + +private: + LensShadingCorrection::Components lscData_; +}; class LscTableLoader { public: int parseLscData(const YamlObject &yamlSets, - std::map<unsigned int, LensShadingCorrection::Components> &lscData); + LensShadingCorrection::ShadingDescriptorMap &lscData); private: std::vector<uint16_t> parseTable(const YamlObject &tuningData, @@ -222,7 +270,7 @@ private: }; int LscTableLoader::parseLscData(const YamlObject &yamlSets, - std::map<unsigned int, LensShadingCorrection::Components> &lscData) + LensShadingCorrection::ShadingDescriptorMap &lscData) { const auto &sets = yamlSets.asList(); @@ -236,8 +284,7 @@ int LscTableLoader::parseLscData(const YamlObject &yamlSets, return -EINVAL; } - LensShadingCorrection::Components &set = lscData[ct]; - + LensShadingCorrection::Components set; set.r = parseTable(yamlSet, "r"); set.gr = parseTable(yamlSet, "gr"); set.gb = parseTable(yamlSet, "gb"); @@ -250,6 +297,9 @@ int LscTableLoader::parseLscData(const YamlObject &yamlSets, << " is missing tables"; return -EINVAL; } + + lscData.emplace( + ct, std::make_unique<LscTableShadingDescriptor>(std::move(set))); } if (lscData.empty()) { @@ -341,7 +391,7 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, return -EINVAL; } - std::map<unsigned int, Components> lscData; + ShadingDescriptorMap lscData; int ret = 0; std::string type = tuningData["type"].get<std::string>("table"); @@ -351,10 +401,11 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, ret = loader.parseLscData(yamlSets, lscData); } else if (type == "polynomial") { LOG(RkISP1Lsc, Debug) << "Loading polynomial LSC data."; - auto loader = LscPolynomialLoader(context.sensorInfo.activeAreaSize, - context.sensorInfo.analogCrop, - xSize_, - ySize_); + /* + * \todo: Most likely the reference frame should be native_size. + * Let's wait how the internal discussions progress. + */ + auto loader = LscPolynomialLoader(context.sensorInfo.activeAreaSize); ret = loader.parseLscData(yamlSets, lscData); } else { LOG(RkISP1Lsc, Error) << "Unsupported LSC data type '" @@ -365,7 +416,7 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, if (ret) return ret; - sets_.setData(std::move(lscData)); + shadingDescriptors_ = std::move(lscData); return 0; } @@ -401,6 +452,14 @@ int LensShadingCorrection::configure(IPAContext &context, yGrad_[i] = std::round(32768 / ySizes_[i]); } + LOG(RkISP1Lsc, Debug) << "Sample LSC data for " << configInfo.analogCrop; + std::map<unsigned int, LensShadingCorrection::Components> shadingData; + for (const auto &[t, descriptor] : shadingDescriptors_) + shadingData[t] = descriptor->sampleForCrop(configInfo.analogCrop, + xSize_, ySize_); + + sets_.setData(std::move(shadingData)); + context.configuration.lsc.enabled = true; return 0; } diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h index 7b68dda1a0d4257c345e0f1b77aa498f8183c92f..3097740a6cb2ce9063a4ba087856987a489b0ab6 100644 --- a/src/ipa/rkisp1/algorithms/lsc.h +++ b/src/ipa/rkisp1/algorithms/lsc.h @@ -8,6 +8,7 @@ #pragma once #include <map> +#include <memory> #include "libipa/interpolator.h" @@ -36,10 +37,22 @@ public: std::vector<uint16_t> b; }; + class ShadingDescriptor + { + public: + virtual ~ShadingDescriptor() = default; + virtual Components sampleForCrop(const Rectangle &cropRectangle, + Span<const double> xSizes, + Span<const double> ySizes) = 0; + }; + + using ShadingDescriptorMap = std::map<unsigned int, std::unique_ptr<ShadingDescriptor>>; + private: void setParameters(rkisp1_cif_isp_lsc_config &config); void copyTable(rkisp1_cif_isp_lsc_config &config, const Components &set0); + ShadingDescriptorMap shadingDescriptors_; ipa::Interpolator<Components> sets_; std::vector<double> xSize_; std::vector<double> ySize_;