@@ -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 a 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::numHCells
+ * \brief Number of horizontal cells of the ISP lsc grid. Used for validating
+ * the list of gains parsed from tuning file
+ *
+ * \var LscDescriptor::numVCells
+ * \brief Number of vertical cells 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 numHCells;
+ unsigned int numVCells;
+ 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.numHCells,
+ descriptor.numVCells)));
+ 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 numHCells,
+ unsigned int numVCells)
{
- static constexpr unsigned int kLscNumSamples =
- RKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX;
+ unsigned int lscNumSamples = numHCells * numVCells;
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 numHCells,
+ unsigned int numVCells);
lsc::ComponentsMap lscData_;
};
@@ -67,8 +67,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" },
+ .numHCells = RKISP1_CIF_ISP_LSC_SAMPLES_MAX,
+ .numVCells = RKISP1_CIF_ISP_LSC_SAMPLES_MAX,
+ .sensorSize = context.sensorInfo.activeAreaSize
+ });
}
std::vector<double> LensShadingCorrection::parseSizes(const ValueNode &tuningData,
@@ -174,10 +178,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]);
}
/**
The current definition of lsc::Components assumes 4 gain vectors named after the colour components supported by the RkISP1 ISP (r, gr, gb and b). As different ISP support different colour channels for their Lsc tables make lsc::Components a map that associates the name of the colour channel to the vector of gains. The use of strings as index for the map comes from the requirement of parsing the tuning file using string identifiers. Pass the strings to use for tuning file parsing to the LscAlgorithm::init() function as part of a newly introduced LscDescriptor type and use the same strings for indexing the gain arrays. The newly introduced LscDescriptor type also provides to the LscAlgorithm class the expected size of the Lsc grid, allowing to remove RkISP1 specific values from the libipa generic implementation. Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> --- src/ipa/libipa/lsc.cpp | 10 +++--- src/ipa/libipa/lsc.h | 4 +-- src/ipa/libipa/lsc_base.cpp | 49 ++++++++++++++++++++-------- src/ipa/libipa/lsc_base.h | 18 ++++++----- src/ipa/libipa/lsc_polynomial.cpp | 65 +++++++++++++++++++------------------ src/ipa/libipa/lsc_polynomial.h | 10 ++---- src/ipa/libipa/lsc_table.cpp | 68 +++++++++++++++++++++++---------------- src/ipa/libipa/lsc_table.h | 9 ++++-- src/ipa/rkisp1/algorithms/lsc.cpp | 20 ++++++++---- 9 files changed, 150 insertions(+), 103 deletions(-)