@@ -86,16 +86,16 @@ namespace lsc {
/**
* \param[in] tuningData The tuning data
- * \param[in] sensorSize The physical sensor size
* \param[in] controls The IPA list of supported controls
+ * \param[in] descriptor The LSC engine descriptor
*
* 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)
+int LscAlgorithm::init(const ValueNode &tuningData, ControlInfoMap::Map &controls,
+ const LscDescriptor &descriptor)
{
polynomial_ = false;
@@ -108,7 +108,7 @@ int LscAlgorithm::init(const ValueNode &tuningData, const Size &sensorSize,
* \todo Most likely the reference frame should be native_size.
* Let's wait how the internal discussions progress.
*/
- impl_ = std::make_unique<LscPolynomial>(sensorSize);
+ impl_ = std::make_unique<LscPolynomial>(descriptor.sensorSize);
polynomial_ = true;
LOG(Lsc, Debug) << "Using polynomial Lsc";
} else {
@@ -123,7 +123,7 @@ int LscAlgorithm::init(const ValueNode &tuningData, const Size &sensorSize,
return -EINVAL;
}
- int ret = impl_->parseLscData(yamlSets);
+ int ret = impl_->parseLscData(yamlSets, descriptor);
if (ret)
return ret;
@@ -38,8 +38,8 @@ struct FrameContext {
class LscAlgorithm
{
public:
- int init(const ValueNode &tuningData, const Size &sensorSize,
- ControlInfoMap::Map &controls);
+ int init(const ValueNode &tuningData, ControlInfoMap::Map &controls,
+ const LscDescriptor &descriptor);
int configure(lsc::ActiveState &state, const Rectangle &analogCrop,
const std::vector<double> &xPos,
@@ -19,23 +19,20 @@ namespace ipa {
namespace lsc {
/**
- * \struct Components
+ * \typedef Components
* \brief Associate colour components with a list of gains
*
* LSC tables are defined as a list of gain values associated to a colour
* component.
*
- * \var Components::r
- * \brief The list of gains for the Red colour component
+ * As different ISP support different colour components (usually 'r', 'gr',
+ * 'gb', 'b' or just 'r', 'g', 'b') this class associates a string
+ * identifier for the colour component to a list of gains.
*
- * \var Components::gr
- * \brief The list of gains for the Green/Red colour component
+ * Each key name shall match an entry in the tuning file.
*
- * \var Components::gb
- * \brief The list of gains for the Green/Blue colour component
- *
- * \var Components::b
- * \brief The list of gains for the Blue colour component
+ * The list of keys is provided to the LscAlgorithm class using \a
+ * LscDescriptor::keys.
*/
/**
@@ -57,13 +54,32 @@ void Interpolator<lsc::Components>::
lsc::Components &dest,
double lambda)
{
- interpolateVector(a.r, b.r, dest.r, lambda);
- interpolateVector(a.gr, b.gr, dest.gr, lambda);
- interpolateVector(a.gb, b.gb, dest.gb, lambda);
- interpolateVector(a.b, b.b, dest.b, lambda);
+ for (auto const &[k, v] : a)
+ interpolateVector(v, b.at(k), dest[k], lambda);
}
#endif
+/**
+ * \struct LscDescriptor
+ * \brief Describe the ISP LSC engine
+ *
+ * \var LscDescriptor::keys
+ * \brief The list of colour components to which a list of gains is associated
+ * with in the tuning file. Used for parsing the tuning file
+ *
+ * \var LscDescriptor::numHSamples
+ * \brief Number of horizontal gain samples of the ISP LSC grid. Used for
+ * validating the list of gains parsed from tuning file
+ *
+ * \var LscDescriptor::numVSamples
+ * \brief Number of vertical gain samples of the ISP LSC grid. Used for
+ * validating the list of gains parsed from tuning file
+ *
+ * \var LscDescriptor::sensorSize
+ * \brief The physical sensor size. This is the largest frame size used to
+ * generate the LSC table. Only used by the polynomial LSC algorithm
+ */
+
/**
* \class LscImplementation
* \brief Pure virtual base class for LSC algorithm implementations
@@ -80,6 +96,11 @@ void Interpolator<lsc::Components>::
* \fn LscImplementation::parseLscData
* \brief Parse \a tuningData
* \param[in] tuningData The tuning data
+ * \param[in] descriptor The LSC engine descriptor
+ *
+ * Parse the tuning file using the \a descriptor to identify the colour
+ * components in the tuning data and validate the size of the loaded gains
+ * tables.
*
* \return 0 on success, a negative error number otherwise
*/
@@ -26,13 +26,7 @@ namespace ipa {
namespace lsc {
-struct Components {
- std::vector<uint16_t> r;
- std::vector<uint16_t> gr;
- std::vector<uint16_t> gb;
- std::vector<uint16_t> b;
-};
-
+using Components = std::map<std::string, std::vector<uint16_t>>;
using ComponentsMap = std::map<unsigned int, Components>;
} /* namespace lsc */
@@ -56,12 +50,20 @@ void Interpolator<lsc::Components>::
double lambda);
#endif /* __DOXYGEN__ */
+struct LscDescriptor {
+ std::vector<std::string> keys;
+ unsigned int numHSamples;
+ unsigned int numVSamples;
+ Size sensorSize;
+};
+
class LscImplementation
{
public:
virtual ~LscImplementation() {}
- virtual int parseLscData(const ValueNode &tuningData) = 0;
+ virtual int parseLscData(const ValueNode &tuningData,
+ const LscDescriptor &descriptor) = 0;
virtual lsc::ComponentsMap
sampleForCrop(const Rectangle &cropRectangle,
@@ -133,44 +133,43 @@ void Polynomial::setReferenceImageSize(const Size &size)
/**
* \brief Parse polynomial LSC data
* \param[in] sets The tuning file content
+ * \param[in] descriptor The LSC engine descriptor
*
* 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)
+int LscPolynomial::parseLscData(const ValueNode &sets,
+ const LscDescriptor &descriptor)
{
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;
+ PolynomialComponents components;
+ for (auto &k : descriptor.keys) {
+ auto polynomial = set[k.c_str()].get<lsc::Polynomial>();
+ if (!polynomial) {
+ LOG(LscPolynomial, Error)
+ << "Missing polynomial for component "
+ << k;
+ return -EINVAL;
+ }
+
+ auto [it, inserted] =
+ components.emplace(std::piecewise_construct,
+ std::forward_as_tuple(k.c_str()),
+ std::forward_as_tuple(*polynomial));
+
+ it->second.setReferenceImageSize(descriptor.sensorSize);
}
- 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)) {
+ auto [it, inserted] = lscData_.emplace(ct, components);
+ if (!inserted) {
LOG(LscPolynomial, Error)
- << "Failed to parse polynomial for "
- << "colour temperature " << ct;
+ << "Multiple sets found for "
+ << "color 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()) {
@@ -210,13 +209,17 @@ LscPolynomial::sampleForCrop(const Rectangle &cropRectangle,
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)
- };
+ for (const auto &[t, c] : lscData_) {
+ lsc::Components comp;
+
+ for (const auto &[k, p] : c) {
+ comp.emplace(std::piecewise_construct,
+ std::forward_as_tuple(k),
+ std::forward_as_tuple(samplePolynomial(p, xPos, yPos,
+ cropRectangle)));
+ }
+
+ components[t] = comp;
}
return components;
@@ -53,12 +53,7 @@ private:
class LscPolynomial : public LscImplementation
{
private:
- struct PolynomialComponents {
- lsc::Polynomial pr;
- lsc::Polynomial pgr;
- lsc::Polynomial pgb;
- lsc::Polynomial pb;
- };
+ using PolynomialComponents = std::map<std::string, lsc::Polynomial>;
using PolynomialComponentsMap = std::map<unsigned int, PolynomialComponents>;
public:
@@ -67,7 +62,8 @@ public:
{
}
- int parseLscData(const ValueNode &sets) override;
+ int parseLscData(const ValueNode &sets,
+ const LscDescriptor &descriptor) override;
lsc::ComponentsMap
sampleForCrop(const Rectangle &cropRectangle,
@@ -7,9 +7,6 @@
#include "lsc_table.h"
-/* \todo Remove RkISP1 from libipa. */
-#include "linux/rkisp1-config.h"
-
namespace libcamera {
LOG_DEFINE_CATEGORY(LscTable)
@@ -29,42 +26,56 @@ namespace ipa {
/**
* \brief Parse tabular LSC data
* \param[in] sets The tuning file content
+ * \param[in] descriptor The LSC engine descriptor
*
* Parse the LSC data in tabular form from the \a sets tuning data.
*
* \return 0 on success or a negative error number otherwise
*/
-int LscTable::parseLscData(const ValueNode &sets)
+int LscTable::parseLscData(const ValueNode &sets,
+ const LscDescriptor &descriptor)
{
for (const auto &set : sets.asList()) {
uint32_t ct = set["ct"].get<uint32_t>(0);
- if (lscData_.count(ct)) {
- LOG(LscTable, Error)
- << "Multiple sets found for color temperature "
- << ct;
- return -EINVAL;
- }
+ int ret = parseLscComponent(set, ct, descriptor);
+ if (ret)
+ return ret;
+ }
- lsc::Components components;
- components.r = parseTable(set, "r");
- components.gr = parseTable(set, "gr");
- components.gb = parseTable(set, "gb");
- components.b = parseTable(set, "b");
+ if (lscData_.empty()) {
+ LOG(LscTable, Error) << "Failed to load any sets";
+ return -EINVAL;
+ }
- if (components.r.empty() || components.gr.empty() ||
- components.gb.empty() || components.b.empty()) {
+ return 0;
+}
+
+int LscTable::parseLscComponent(const ValueNode &yamlSet,
+ unsigned int ct, const LscDescriptor &descriptor)
+{
+ lsc::Components component;
+ for (auto &k : descriptor.keys) {
+ auto [it, inserted] = component.emplace(
+ std::piecewise_construct,
+ std::forward_as_tuple(k.c_str()),
+ std::forward_as_tuple(parseTable(yamlSet,
+ k.c_str(),
+ descriptor.numHSamples,
+ descriptor.numVSamples)));
+ if (!inserted || it->second.empty()) {
LOG(LscTable, Error)
- << "Set for color temperature " << ct
- << " is missing tables";
+ << "Set " << k << " for color temperature "
+ << ct << " is missing";
return -EINVAL;
}
-
- lscData_.emplace(ct, std::move(components));
}
- if (lscData_.empty()) {
- LOG(LscTable, Error) << "Failed to load any sets";
+ auto [it, inserted] = lscData_.emplace(ct, component);
+ if (!inserted) {
+ LOG(LscTable, Error)
+ << "Multiple sets found for color temperature "
+ << ct;
return -EINVAL;
}
@@ -72,17 +83,18 @@ int LscTable::parseLscData(const ValueNode &sets)
}
std::vector<uint16_t> LscTable::parseTable(const ValueNode &tuningData,
- const char *prop)
+ const char *prop,
+ unsigned int numHSamples,
+ unsigned int numVSamples)
{
- static constexpr unsigned int kLscNumSamples =
- RKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX;
+ unsigned int lscNumSamples = numHSamples * numVSamples;
std::vector<uint16_t> table =
tuningData[prop].get<std::vector<uint16_t>>().value_or(utils::defopt);
- if (table.size() != kLscNumSamples) {
+ if (table.size() != lscNumSamples) {
LOG(LscTable, Error)
<< "Invalid '" << prop << "' values: expected "
- << kLscNumSamples
+ << lscNumSamples
<< " elements, got " << table.size();
return {};
}
@@ -26,7 +26,8 @@ namespace ipa {
class LscTable : public LscImplementation
{
public:
- int parseLscData(const ValueNode &sets) override;
+ int parseLscData(const ValueNode &sets,
+ const LscDescriptor &descriptor) override;
lsc::ComponentsMap
sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,
@@ -39,8 +40,12 @@ public:
}
private:
+ int parseLscComponent(const ValueNode &yamlSet,
+ unsigned int ct, const LscDescriptor &descriptor);
std::vector<uint16_t> parseTable(const ValueNode &tuningData,
- const char *prop);
+ const char *prop,
+ unsigned int numHSamples,
+ unsigned int numVSamples);
lsc::ComponentsMap lscData_;
};
@@ -123,8 +123,12 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context,
xPos_ = sizesListToPositions(xSize_);
yPos_ = sizesListToPositions(ySize_);
- return lscAlgo_.init(tuningData, context.sensorInfo.activeAreaSize,
- context.ctrlMap);
+ return lscAlgo_.init(tuningData, context.ctrlMap, {
+ .keys = { "r", "gr", "gb", "b" },
+ .numHSamples = RKISP1_CIF_ISP_LSC_SAMPLES_MAX,
+ .numVSamples = RKISP1_CIF_ISP_LSC_SAMPLES_MAX,
+ .sensorSize = context.sensorInfo.activeAreaSize
+ });
}
/**
@@ -173,10 +177,14 @@ void LensShadingCorrection::setParameters(rkisp1_cif_isp_lsc_config &config)
void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,
const lsc::Components &set)
{
- std::copy(set.r.begin(), set.r.end(), &config.r_data_tbl[0][0]);
- std::copy(set.gr.begin(), set.gr.end(), &config.gr_data_tbl[0][0]);
- std::copy(set.gb.begin(), set.gb.end(), &config.gb_data_tbl[0][0]);
- std::copy(set.b.begin(), set.b.end(), &config.b_data_tbl[0][0]);
+ const auto &r = set.at("r");
+ std::copy(r.begin(), r.end(), &config.r_data_tbl[0][0]);
+ const auto &gr = set.at("gr");
+ std::copy(gr.begin(), gr.end(), &config.gr_data_tbl[0][0]);
+ const auto &gb = set.at("gb");
+ std::copy(gb.begin(), gb.end(), &config.gb_data_tbl[0][0]);
+ const auto &b = set.at("b");
+ std::copy(b.begin(), b.end(), &config.b_data_tbl[0][0]);
}
/**