@@ -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;
}
@@ -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_;