From patchwork Mon Jul 20 14:59:45 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 27419 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id E4C42C333D for ; Mon, 20 Jul 2026 15:00:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6542267EA4; Mon, 20 Jul 2026 17:00:20 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="rLN1wwr9"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5033D67E83 for ; Mon, 20 Jul 2026 16:59:56 +0200 (CEST) Received: from [192.168.1.106] (mob-5-90-63-152.net.vodafone.it [5.90.63.152]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 671811CE9; Mon, 20 Jul 2026 16:58:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1784559537; bh=dlfNgaxvpp06Pxl62gjETV+oyFIXVXC6rt1lzcZEpYo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=rLN1wwr9zqi/qgIR9hvlKTL6j2N52d1il4reeM25lYqKzdLQV2VrNtfy3GjuXWe2C FY3Mt7Z0qbvNhFEWXevh4MyrfnHMD1PiurGtUgN54pIrhD4cKHSzD3p//MSFdwNA9W WJqUjgl2kSGIymB56WmoKLL2mxsuad6LCNNOMrro= From: Jacopo Mondi Date: Mon, 20 Jul 2026 16:59:45 +0200 Subject: [PATCH v6 27/31] ipa: libipa: lsc: Quantize lsc gains in IPA MIME-Version: 1.0 Message-Id: <20260720-libipa-algorithms-v6-27-ececb73f97cb@ideasonboard.com> References: <20260720-libipa-algorithms-v6-0-ececb73f97cb@ideasonboard.com> In-Reply-To: <20260720-libipa-algorithms-v6-0-ececb73f97cb@ideasonboard.com> To: libcamera-devel@lists.libcamera.org, Stefan Klug , Milan Zamazal Cc: Jacopo Mondi X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=6809; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=dlfNgaxvpp06Pxl62gjETV+oyFIXVXC6rt1lzcZEpYo=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBqXjfap9BmU1yuAc8zHJbfjCem5Bbqplt9GgcTC p3rSAbANH2JAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCal432gAKCRByNAaPFqFW PHW5D/92cTnLNYkHcsM8jwT3I881kfdRWTW1qJ4EBqduADra+BhV+lhYMZy9oyZF84IqLSxiZCB AUZCXDThq46QuBRM7r05g8Y/PN71TwJdlu4pkW5dfKoH5CX4Cg9tPi7phAAn4iviowGNIBSGoHO X48CKdtorsQgJlIu76Ty1wyGRgT0ArEtd3DQTwVlE7cDT52z3rWIHaPZhrkN0btQV+Mcvq+yvR1 EY9Ef9Rzi8hs7lMcNQPHIL0UzToF9l+NU5cEePw+P6kZbKm88JvhHRZMhWrhw/6UUADbjydt+XG jNe0b0jY1N4vcVgn1L/hLwWWLGobfDZzssk0nqzYvCTBoUedcbUf49ahWhcu8ikD6ianWnD+t6A jpZV8xisjVcN5GXGZMlMRMM4D6C0GRuszFo8XN0lDNFtYTEt7enSfM0aBcCNPFaqoNXUf/2VN3Z VI3eFFlvMG3XCOAWEag8w8p5hL+QLfQi6xRa/QPKu/LuM6wvIR4L6fBM4e6gd6oLPE5dqQTveOZ g8dY8c5UqxHrsku5oyHnNDr0Ua5ejXQBzX+MIQdRbi8Iqw83bGlyU4LNv4e2W6fsalxZw3PmKwa 0PKbypLNhQ6jVxRy7kuNwybPmHQ0L5oW9vt8CEu7wj8tFqatnQ32FBDd3YW+5fJYDykZ2bDUOBd R3HXq53IaMtYadQ== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The libIPA Lsc algorithm currently assumes the register format of the RkISP1 platform (16 bits Q2.10 format), as that's where the implementation has been derived from. Move the register quantization to the plaltform IPA and use 'floats' as the exchange format for the table-based and polynomial-based LSC implementations. Signed-off-by: Jacopo Mondi --- src/ipa/libipa/lsc_base.h | 2 +- src/ipa/libipa/lsc_polynomial.cpp | 17 +++++------------ src/ipa/libipa/lsc_polynomial.h | 8 ++++---- src/ipa/libipa/lsc_table.cpp | 6 +++--- src/ipa/libipa/lsc_table.h | 2 +- src/ipa/rkisp1/algorithms/lsc.cpp | 34 ++++++++++++++++++++++++++-------- 6 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/ipa/libipa/lsc_base.h b/src/ipa/libipa/lsc_base.h index b0b9b3b0712d..386cac55be34 100644 --- a/src/ipa/libipa/lsc_base.h +++ b/src/ipa/libipa/lsc_base.h @@ -26,7 +26,7 @@ namespace ipa { namespace lsc { -using Components = std::map>; +using Components = std::map>; using ComponentsMap = std::map; } /* namespace lsc */ diff --git a/src/ipa/libipa/lsc_polynomial.cpp b/src/ipa/libipa/lsc_polynomial.cpp index c61c85fbf2b2..e31a63e06cc8 100644 --- a/src/ipa/libipa/lsc_polynomial.cpp +++ b/src/ipa/libipa/lsc_polynomial.cpp @@ -218,7 +218,7 @@ LscPolynomial::sampleForCrop(const Rectangle &cropRectangle, return components; } -std::vector +std::vector LscPolynomial::samplePolynomial(const lsc::Polynomial &poly, Span xPositions, Span yPositions, @@ -229,7 +229,7 @@ LscPolynomial::samplePolynomial(const lsc::Polynomial &poly, double y0 = cropRectangle.y / m; double w = cropRectangle.width / m; double h = cropRectangle.height / m; - std::vector samples; + std::vector samples; samples.reserve(xPositions.size() * yPositions.size()); @@ -237,16 +237,9 @@ LscPolynomial::samplePolynomial(const lsc::Polynomial &poly, 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( - poly.sampleAtNormalizedPixelPos(xp, yp) * - 1024); - v = std::clamp(v, 1024, 4095); - samples.push_back(v); + + samples.push_back(static_cast + (poly.sampleAtNormalizedPixelPos(xp, yp))); } } return samples; diff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h index 6d19e46a50b7..8d526531075b 100644 --- a/src/ipa/libipa/lsc_polynomial.h +++ b/src/ipa/libipa/lsc_polynomial.h @@ -65,10 +65,10 @@ public: std::vector xPos, std::vector yPos) override; private: - std::vector samplePolynomial(const lsc::Polynomial &poly, - Span xPositions, - Span yPositions, - const Rectangle &cropRectangle); + std::vector samplePolynomial(const lsc::Polynomial &poly, + Span xPositions, + Span yPositions, + const Rectangle &cropRectangle); PolynomialComponentsMap lscData_; }; diff --git a/src/ipa/libipa/lsc_table.cpp b/src/ipa/libipa/lsc_table.cpp index 92e24bc5160a..33f6182de1bd 100644 --- a/src/ipa/libipa/lsc_table.cpp +++ b/src/ipa/libipa/lsc_table.cpp @@ -82,15 +82,15 @@ int LscTable::parseLscComponent(const ValueNode &yamlSet, return 0; } -std::vector LscTable::parseTable(const ValueNode &tuningData, +std::vector LscTable::parseTable(const ValueNode &tuningData, const char *prop, unsigned int numHSamples, unsigned int numVSamples) { unsigned int lscNumSamples = numHSamples * numVSamples; - std::vector table = - tuningData[prop].get>().value_or(utils::defopt); + std::vector table = + tuningData[prop].get>().value_or(utils::defopt); if (table.size() != lscNumSamples) { LOG(LscTable, Error) << "Invalid '" << prop << "' values: expected " diff --git a/src/ipa/libipa/lsc_table.h b/src/ipa/libipa/lsc_table.h index a33208761c15..6d9b0c692b7f 100644 --- a/src/ipa/libipa/lsc_table.h +++ b/src/ipa/libipa/lsc_table.h @@ -42,7 +42,7 @@ public: private: int parseLscComponent(const ValueNode &yamlSet, unsigned int ct, const LscDescriptor &descriptor); - std::vector parseTable(const ValueNode &tuningData, + std::vector parseTable(const ValueNode &tuningData, const char *prop, unsigned int numHSamples, unsigned int numVSamples); diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 7a95bfcfb93a..dba1a01118ee 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -177,14 +177,32 @@ void LensShadingCorrection::setParameters(rkisp1_cif_isp_lsc_config &config) void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config, const lsc::Components &set) { - 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 hardware uses 2.10 fixed point format and limits the legal values + * to [1..3.999]. Scale and clamp the sampled values accordingly. + */ + std::vector regs; + regs.reserve(RKISP1_CIF_ISP_LSC_SAMPLES_MAX * + RKISP1_CIF_ISP_LSC_SAMPLES_MAX); + + for (const float &f : set.at("r")) + regs.emplace_back(std::clamp(static_cast(f * 1024), 1024, 4095)); + std::copy(regs.begin(), regs.end(), &config.r_data_tbl[0][0]); + + regs = {}; + for (const float &f : set.at("gr")) + regs.emplace_back(std::clamp(static_cast(f * 1024), 1024, 4095)); + std::copy(regs.begin(), regs.end(), &config.gr_data_tbl[0][0]); + + regs = {}; + for (const float &f : set.at("gb")) + regs.emplace_back(std::clamp(static_cast(f * 1024), 1024, 4095)); + std::copy(regs.begin(), regs.end(), &config.gb_data_tbl[0][0]); + + regs = {}; + for (const float &f : set.at("b")) + regs.emplace_back(std::clamp(static_cast(f * 1024), 1024, 4095)); + std::copy(regs.begin(), regs.end(), &config.b_data_tbl[0][0]); } /**