diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 761e5a76..c7a40a64 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -72,115 +72,54 @@ namespace { constexpr int kColourTemperatureQuantization = 10; -class LscPolynomialLoader +class LscPolynomialShadingDescriptor : public LensShadingCorrection::ShadingDescriptor { public: - LscPolynomialLoader(const Size &sensorSize, - const Rectangle &cropRectangle, - const std::vector &xSizes, - const std::vector &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 &lscData); + LensShadingCorrection::Components sampleForCrop(const Rectangle &cropRectangle, + Span xSizes, + Span ySizes) override; private: - std::vector sizesListToPositions(const std::vector &sizes); std::vector samplePolynomial(const LscPolynomial &poly, Span xPositions, Span yPositions, const Rectangle &cropRectangle); - Size sensorSize_; - Rectangle cropRectangle_; - const std::vector &xSizes_; - const std::vector &ySizes_; + std::vector sizesListToPositions(Span sizes); + + LscPolynomial pr_; + LscPolynomial pgr_; + LscPolynomial pgb_; + LscPolynomial pb_; }; -int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, - std::map &lscData) +LensShadingCorrection::Components +LscPolynomialShadingDescriptor::sampleForCrop(const Rectangle &cropRectangle, + Span xSizes, + Span ySizes) { - const auto &sets = yamlSets.asList(); - for (const auto &yamlSet : sets) { - std::optional pr, pgr, pgb, pb; - uint32_t ct = yamlSet["ct"].get(0); + std::vector xPos = sizesListToPositions(xSizes); + std::vector yPos = sizesListToPositions(ySizes); - if (lscData.count(ct)) { - LOG(RkISP1Lsc, Error) - << "Multiple sets found for " - << "color temperature " << ct; - return -EINVAL; - } - - LensShadingCorrection::Components &set = lscData[ct]; - pr = yamlSet["r"].get(); - pgr = yamlSet["gr"].get(); - pgb = yamlSet["gb"].get(); - pb = yamlSet["b"].get(); - - 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_); - - std::vector xPos = sizesListToPositions(xSizes_); - std::vector 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_); - } - - if (lscData.empty()) { - LOG(RkISP1Lsc, Error) << "Failed to load any sets"; - return -EINVAL; - } - - return 0; + 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) + }; } -/* - * 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 LscPolynomialLoader::sizesListToPositions(const std::vector &sizes) -{ - const int half = sizes.size(); - std::vector 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; -} - -std::vector LscPolynomialLoader::samplePolynomial(const LscPolynomial &poly, - Span xPositions, - Span yPositions, - const Rectangle &cropRectangle) +std::vector +LscPolynomialShadingDescriptor::samplePolynomial(const LscPolynomial &poly, + Span xPositions, + Span yPositions, + const Rectangle &cropRectangle) { double m = poly.getM(); double x0 = cropRectangle.x / m; @@ -203,18 +142,127 @@ std::vector LscPolynomialLoader::samplePolynomial(const LscPolynomial int v = static_cast( poly.sampleAtNormalizedPixelPos(xp, yp) * 1024); - v = std::min(std::max(v, 1024), 4095); + 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 +LscPolynomialShadingDescriptor::sizesListToPositions(Span sizes) +{ + const int half = sizes.size(); + std::vector 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_; +}; + +int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, + LensShadingCorrection::ShadingDescriptorMap &lscData) +{ + const auto &sets = yamlSets.asList(); + for (const auto &yamlSet : sets) { + std::optional pr, pgr, pgb, pb; + uint32_t ct = yamlSet["ct"].get(0); + + if (lscData.count(ct)) { + LOG(RkISP1Lsc, Error) + << "Multiple sets found for " + << "color temperature " << ct; + return -EINVAL; + } + + pr = yamlSet["r"].get(); + pgr = yamlSet["gr"].get(); + pgb = yamlSet["gb"].get(); + pb = yamlSet["b"].get(); + + 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( + ct, std::make_unique( + *pr, *pgr, *pgb, *pb)); + } + + if (lscData.empty()) { + LOG(RkISP1Lsc, Error) << "Failed to load any sets"; + return -EINVAL; + } + + return 0; +} + +class LscTableShadingDescriptor : public LensShadingCorrection::ShadingDescriptor +{ +public: + LscTableShadingDescriptor(LensShadingCorrection::Components components) + : lscData_(std::move(components)) + { + } + + LensShadingCorrection::Components + sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle, + [[maybe_unused]] Span xSizes, + [[maybe_unused]] Span ySizes) override + { + LOG(RkISP1Lsc, Warning) + << "Tabular LSC data doesn't support resampling"; + return lscData_; + } + +private: + LensShadingCorrection::Components lscData_; +}; + class LscTableLoader { public: int parseLscData(const YamlObject &yamlSets, - std::map &lscData); + LensShadingCorrection::ShadingDescriptorMap &lscData); private: std::vector parseTable(const YamlObject &tuningData, @@ -222,7 +270,7 @@ private: }; int LscTableLoader::parseLscData(const YamlObject &yamlSets, - std::map &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(std::move(set))); } if (lscData.empty()) { @@ -341,7 +391,7 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, return -EINVAL; } - std::map lscData; + ShadingDescriptorMap lscData; int ret = 0; std::string type = tuningData["type"].get("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 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 7b68dda1..3097740a 100644 --- a/src/ipa/rkisp1/algorithms/lsc.h +++ b/src/ipa/rkisp1/algorithms/lsc.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include "libipa/interpolator.h" @@ -36,10 +37,22 @@ public: std::vector b; }; + class ShadingDescriptor + { + public: + virtual ~ShadingDescriptor() = default; + virtual Components sampleForCrop(const Rectangle &cropRectangle, + Span xSizes, + Span ySizes) = 0; + }; + + using ShadingDescriptorMap = std::map>; + private: void setParameters(rkisp1_cif_isp_lsc_config &config); void copyTable(rkisp1_cif_isp_lsc_config &config, const Components &set0); + ShadingDescriptorMap shadingDescriptors_; ipa::Interpolator sets_; std::vector xSize_; std::vector ySize_;