From patchwork Thu Jan 8 16:05:44 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25691 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 EBB65BE08B for ; Thu, 8 Jan 2026 16:06:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A141C61FC4; Thu, 8 Jan 2026 17:06:29 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="pF/wRPCO"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3EB28615B2 for ; Thu, 8 Jan 2026 17:06:28 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id C456E63B; Thu, 8 Jan 2026 17:06:05 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888365; bh=OcEp1RGR9Yo43utM4YX0sN8zvzSy2va566Bm6G86NKo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=pF/wRPCOHi3adzWL68FRfeVjCBCQ/5L0t2N45mA+ISozlYFxIFFDjD/tYSJsWE+v3 PX/F/skfHhJLd5aJQQI9RZGiR0nGsytIjnGAlRXI5Mbvtr/m3thSXwjhVHy/7lgXWL aJ4/yIFgicOPrKdmaaR0ZcaNQH4mczsIfzhUIGdI= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:44 +0100 Subject: [PATCH v2 01/15] ipa: rkisp1: lsc: Drop unused member variable MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-1-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , Rui Wang X-Mailer: b4 0.14.2 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 Components::ct member is not used anywhere. Drop it. Signed-off-by: Stefan Klug Reviewed-by: Barnabás Pőcze Reviewed-by: Rui Wang --- Changes in v2: - Collected tags --- src/ipa/rkisp1/algorithms/lsc.cpp | 2 -- src/ipa/rkisp1/algorithms/lsc.h | 1 - 2 files changed, 3 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index e7301bfec86393c4aad4e645800513d8c262e6f9..ab0ada4eed46bc3fdbce17377164a7fbfb321957 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -113,7 +113,6 @@ public: return -EINVAL; } - set.ct = ct; pr->setReferenceImageSize(sensorSize_); pgr->setReferenceImageSize(sensorSize_); pgb->setReferenceImageSize(sensorSize_); @@ -221,7 +220,6 @@ public: LensShadingCorrection::Components &set = lscData[ct]; - set.ct = ct; set.r = parseTable(yamlSet, "r"); set.gr = parseTable(yamlSet, "gr"); set.gb = parseTable(yamlSet, "gb"); diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h index 5a0824e36dd5b45660514ce295fc2f42fdc4fa30..0e3745d5589c2ea94f63efbbb0eb51670cbc2793 100644 --- a/src/ipa/rkisp1/algorithms/lsc.h +++ b/src/ipa/rkisp1/algorithms/lsc.h @@ -30,7 +30,6 @@ public: RkISP1Params *params) override; struct Components { - uint32_t ct; std::vector r; std::vector gr; std::vector gb; From patchwork Thu Jan 8 16:05:45 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25692 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 81B1EBE08B for ; Thu, 8 Jan 2026 16:06:32 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 38BE461FBE; Thu, 8 Jan 2026 17:06:32 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="M6aRr7w6"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BC41661FA0 for ; Thu, 8 Jan 2026 17:06:31 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 3C68E19D0; Thu, 8 Jan 2026 17:06:09 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888369; bh=H02CYr/W/mR0vOF0IrXmTD9xh4WEHezABJY6Jg+EPvo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=M6aRr7w6DApUZdIx3kC4tzQqIojiLUZJNMzxSkkCqsSezdnBsqtvyQZThVnhoUMpL OIP4pA+6uAvXu5G8qmbli/COtmDWhOGJQqv5Y+Ofpc59BQ4DHRrQ3Fw/gOyP6+k2vt JnLT+7Y+ALacoOMwDkK9mCP0+EnRIvZtQXXJC/3s= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:45 +0100 Subject: [PATCH v2 02/15] ipa: rkisp1: lsc: Drop unused function declaration MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-2-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , Laurent Pinchart X-Mailer: b4 0.14.2 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 interpolateTable() function is not implemented anywhere. Drop the declaration. Signed-off-by: Stefan Klug Reviewed-by: Barnabás Pőcze Reviewed-by: Laurent Pinchart --- Changes in v2: - Collected tags --- src/ipa/rkisp1/algorithms/lsc.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h index 0e3745d5589c2ea94f63efbbb0eb51670cbc2793..7b68dda1a0d4257c345e0f1b77aa498f8183c92f 100644 --- a/src/ipa/rkisp1/algorithms/lsc.h +++ b/src/ipa/rkisp1/algorithms/lsc.h @@ -39,9 +39,6 @@ public: private: void setParameters(rkisp1_cif_isp_lsc_config &config); void copyTable(rkisp1_cif_isp_lsc_config &config, const Components &set0); - void interpolateTable(rkisp1_cif_isp_lsc_config &config, - const Components &set0, const Components &set1, - const uint32_t ct); ipa::Interpolator sets_; std::vector xSize_; From patchwork Thu Jan 8 16:05:46 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25693 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 0C6D5BE08B for ; Thu, 8 Jan 2026 16:06:37 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CE45D61FC0; Thu, 8 Jan 2026 17:06:36 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XVNClCEz"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2696561FA0 for ; Thu, 8 Jan 2026 17:06:35 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 9DFE81C7B; Thu, 8 Jan 2026 17:06:12 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888372; bh=XclvvXKia3KXTQl/qKvBdoELOBtaOgq+NkY74Ldf5HU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=XVNClCEzd1eYPsfr1yJKYhteKkootTuhP1CCndJlT71YMI1//KsUnoXA5JyI2jMxi 9igaVNzLY1jk19e5B71Wm/+9qc+95U7veQwKY1vBto4La6Yl/TDrkMY86F2EuDTZpV cktP4vc+QuDjuzbm0TPb7Hq5LSrVIR6oaTZIiX+Y= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:46 +0100 Subject: [PATCH v2 03/15] ipa: rkisp1: lsc: Replace assert with ASSERT MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-3-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , Rui Wang X-Mailer: b4 0.14.2 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" Replace assert() by ASSERT() and drop a set of unnecessary curly braces. Those were noticed in the former review but after the series was applied. Fix them now. Signed-off-by: Stefan Klug Reviewed-by: Barnabás Pőcze Reviewed-by: Rui Wang --- Changes in v2: - Collected tags --- src/ipa/rkisp1/algorithms/lsc.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index ab0ada4eed46bc3fdbce17377164a7fbfb321957..c581e6441853d18618284b51bfa25c25e1fc8083 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -33,11 +33,10 @@ template void interpolateVector(const std::vector &a, const std::vector &b, std::vector &dest, double lambda) { - assert(a.size() == b.size()); + ASSERT(a.size() == b.size()); dest.resize(a.size()); - for (size_t i = 0; i < a.size(); i++) { + for (size_t i = 0; i < a.size(); i++) dest[i] = a[i] * (1.0 - lambda) + b[i] * lambda; - } } template<> @@ -167,8 +166,8 @@ private: double h = cropRectangle_.height / m; std::vector res; - assert(xSizes_.size() * 2 + 1 == k); - assert(ySizes_.size() * 2 + 1 == k); + ASSERT(xSizes_.size() * 2 + 1 == k); + ASSERT(ySizes_.size() * 2 + 1 == k); res.reserve(k * k); From patchwork Thu Jan 8 16:05:47 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25694 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 C9BF9BE08B for ; Thu, 8 Jan 2026 16:06:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 81BD461FA0; Thu, 8 Jan 2026 17:06:38 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="vqc5Q4OP"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8319561FA0 for ; Thu, 8 Jan 2026 17:06:37 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 119DF1C7B; Thu, 8 Jan 2026 17:06:15 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888375; bh=OidrM49Hyx9J+ESnrJB6SegC1GcDkuwWcSVuhdfK2Uc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=vqc5Q4OP/WJrkK9miQI8aDicqBma1ajoIiMA6IURU6hchBWsUa5J0OjicmiasGVo3 YrrG0JCAeX1xoCJ2aXZwFpxvb2W0DgqmkFN4h76e3Nb1R3pBOD/NEpJ2I1Q9C2A2HN ERD/gZVlKqfPy7xSQfwqcrwwL85Eu9A9Gl5cEEdk= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:47 +0100 Subject: [PATCH v2 04/15] ipa: rkisp1: lsc: Rename res to positions MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-4-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , Rui Wang X-Mailer: b4 0.14.2 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" Rename the res variable to positions which better describes the intent. This was commented in review after being merged. While at it, improve the documentation a bit. Signed-off-by: Stefan Klug Reviewed-by: Barnabás Pőcze Reviewed-by: Rui Wang --- Changes in v2: - Collected tags --- src/ipa/rkisp1/algorithms/lsc.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index c581e6441853d18618284b51bfa25c25e1fc8083..bb58386ae646ad6089322ba63d2a9e89664884d2 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -132,9 +132,11 @@ public: private: /* - * The lsc grid has custom spacing defined on half the range (see - * parseSizes() for details). For easier handling this function converts - * the spaces vector to positions and mirrors them. E.g.: + * 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 @@ -142,17 +144,17 @@ private: std::vector sizesListToPositions(const std::vector &sizes) { const int half = sizes.size(); - std::vector res(half * 2 + 1); + std::vector positions(half * 2 + 1); double x = 0.0; - res[half] = 0.5; + positions[half] = 0.5; for (int i = 1; i <= half; i++) { x += sizes[half - i]; - res[half - i] = 0.5 - x; - res[half + i] = 0.5 + x; + positions[half - i] = 0.5 - x; + positions[half + i] = 0.5 + x; } - return res; + return positions; } std::vector samplePolynomial(const LscPolynomial &poly) From patchwork Thu Jan 8 16:05:48 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25695 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 62921BE08B for ; Thu, 8 Jan 2026 16:06:42 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1910461FBF; Thu, 8 Jan 2026 17:06:42 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="HakhhJb2"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8D7F161FBF for ; Thu, 8 Jan 2026 17:06:40 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 0F4111E2F; Thu, 8 Jan 2026 17:06:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888378; bh=Q66L+qBP3d9HUh5DEB9HQOwvALS5AmnZ9rrQY4rui1k=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=HakhhJb2Obnp1o3+cu/EsjLmxarK8gU9tyiJ34+K+wzwqwSRRiZJ0zt5HWtKSmebM LOLOdJgyTdIDDNSLKn5mknnsy1G4QwGBt0+tBC672vI0PXzOxeeohQDz1UK6F3Arvd Nq6IjerEezLXtnhUeMgzHthvPoqdTlVWAAt8Eblw= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:48 +0100 Subject: [PATCH v2 05/15] ipa: rkisp1: lsc: Rename res to ret MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-5-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , Rui Wang X-Mailer: b4 0.14.2 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" Rename res to ret as that is used in libcamera for return codes. Signed-off-by: Stefan Klug Reviewed-by: Barnabás Pőcze Reviewed-by: Rui Wang --- Changes in v2: - Restored old variable order - Collected tags --- src/ipa/rkisp1/algorithms/lsc.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index bb58386ae646ad6089322ba63d2a9e89664884d2..68e262a2b057d12a9019a6a92c1b300272b04c4d 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -321,27 +321,28 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, } std::map lscData; - int res = 0; + int ret = 0; + std::string type = tuningData["type"].get("table"); if (type == "table") { LOG(RkISP1Lsc, Debug) << "Loading tabular LSC data."; auto loader = LscTableLoader(); - res = loader.parseLscData(yamlSets, lscData); + 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_); - res = loader.parseLscData(yamlSets, lscData); + ret = loader.parseLscData(yamlSets, lscData); } else { LOG(RkISP1Lsc, Error) << "Unsupported LSC data type '" << type << "'"; - res = -EINVAL; + ret = -EINVAL; } - if (res) - return res; + if (ret) + return ret; sets_.setData(std::move(lscData)); From patchwork Thu Jan 8 16:05:49 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25696 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 D4B0BBE08B for ; Thu, 8 Jan 2026 16:06:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8D41F61FC8; Thu, 8 Jan 2026 17:06:45 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="lLFmgPtO"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EBC0D61FA0 for ; Thu, 8 Jan 2026 17:06:43 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 7CE0819D0; Thu, 8 Jan 2026 17:06:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888381; bh=jpVW171WvOTT4/C/X32xZQLYDdf8/dod1BqJw5h2R6g=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=lLFmgPtOrsEJC259GeX1A85IxmMQWaIxN+x1EmF7pPmpXiET355bDJYfNDwMsH+DN QlWIbF69W5f4HYyR0fHp1afGm9s2gxehPohYVLH/N28gdAxxa1e6HIevBYRoWZWmE3 SMm4ffWt3/Po7woHNIoiOlXsFrYBEwAF5UnQwAk0= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:49 +0100 Subject: [PATCH v2 06/15] ipa: rkisp1: lsc: Rename res to samples MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-6-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , Rui Wang X-Mailer: b4 0.14.2 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" Rename res to samples to better describe the intent. This was noted in review after the series was merged. Signed-off-by: Stefan Klug Reviewed-by: Barnabás Pőcze Reviewed-by: Rui Wang --- Changes in v2: - Collected tags --- src/ipa/rkisp1/algorithms/lsc.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 68e262a2b057d12a9019a6a92c1b300272b04c4d..1b15c11093cfd63bf740558da9450ac836b12004 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -166,12 +166,12 @@ private: double y0 = cropRectangle_.y / m; double w = cropRectangle_.width / m; double h = cropRectangle_.height / m; - std::vector res; + std::vector samples; ASSERT(xSizes_.size() * 2 + 1 == k); ASSERT(ySizes_.size() * 2 + 1 == k); - res.reserve(k * k); + samples.reserve(k * k); std::vector xPos(sizesListToPositions(xSizes_)); std::vector yPos(sizesListToPositions(ySizes_)); @@ -189,10 +189,10 @@ private: poly.sampleAtNormalizedPixelPos(xp, yp) * 1024); v = std::min(std::max(v, 1024), 4095); - res.push_back(v); + samples.push_back(v); } } - return res; + return samples; } Size sensorSize_; From patchwork Thu Jan 8 16:05:50 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25697 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 83B80BE08B for ; Thu, 8 Jan 2026 16:06:49 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3C37561FC5; Thu, 8 Jan 2026 17:06:49 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Dhw6jhnS"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1BB8161FBF for ; Thu, 8 Jan 2026 17:06:47 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 813B363B; Thu, 8 Jan 2026 17:06:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888384; bh=FZ8GonHX/9GBtesyrRJ6bQHXD74/oO2vTKfx8iChULw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Dhw6jhnSpIvoM+v3zrhZgremmNVJ/h7hY95e14K+R9ZeDFzvPpXG+sCMaxRNjsQfT UwRBb5p0RfphiZN3TTfiFSjGqxbFlx76xO03NRlqkfXGgrkA3Jvs51HBbkRws3ueYB 0uoVMi0bY5CA8b97hRmhC6E3B9TvaE05Z8uGuxjU= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:50 +0100 Subject: [PATCH v2 07/15] ipa: rksip1: lsc: Move function definitions out of class MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-7-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , Rui Wang X-Mailer: b4 0.14.2 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" Move the function definitions out of the related classes. This was noted in review after the series was already merged. After trying it out I must admit that it really improves readability and reduces the indentation level by one. Signed-off-by: Stefan Klug Reviewed-by: Barnabás Pőcze Reviewed-by: Rui Wang --- Note: This patch contains no functional changes. `git diff --ignore-space-change` helps in verifying that. Changes in v2: - Collected tags --- src/ipa/rkisp1/algorithms/lsc.cpp | 314 ++++++++++++++++++++------------------ 1 file changed, 163 insertions(+), 151 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 1b15c11093cfd63bf740558da9450ac836b12004..1962d18d148b4abac6e601ec36e0c68944a6191c 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -85,184 +85,196 @@ public: } int parseLscData(const YamlObject &yamlSets, - std::map &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; - } - - 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_); - set.r = samplePolynomial(*pr); - set.gr = samplePolynomial(*pgr); - set.gb = samplePolynomial(*pgb); - set.b = samplePolynomial(*pb); + std::map &lscData); + +private: + std::vector sizesListToPositions(const std::vector &sizes); + std::vector samplePolynomial(const LscPolynomial &poly); + + Size sensorSize_; + Rectangle cropRectangle_; + const std::vector &xSizes_; + const std::vector &ySizes_; +}; + +int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, + std::map &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; } - if (lscData.empty()) { - LOG(RkISP1Lsc, Error) << "Failed to load any sets"; + 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; } - return 0; + pr->setReferenceImageSize(sensorSize_); + pgr->setReferenceImageSize(sensorSize_); + pgb->setReferenceImageSize(sensorSize_); + pb->setReferenceImageSize(sensorSize_); + set.r = samplePolynomial(*pr); + set.gr = samplePolynomial(*pgr); + set.gb = samplePolynomial(*pgb); + set.b = samplePolynomial(*pb); } -private: - /* - * 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 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; - } + if (lscData.empty()) { + LOG(RkISP1Lsc, Error) << "Failed to load any sets"; + return -EINVAL; + } - return positions; + 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 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; } - std::vector samplePolynomial(const LscPolynomial &poly) - { - constexpr int k = RKISP1_CIF_ISP_LSC_SAMPLES_MAX; - - 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 samples; - - ASSERT(xSizes_.size() * 2 + 1 == k); - ASSERT(ySizes_.size() * 2 + 1 == k); - - samples.reserve(k * k); - - std::vector xPos(sizesListToPositions(xSizes_)); - std::vector yPos(sizesListToPositions(ySizes_)); - - for (int y = 0; y < k; y++) { - for (int x = 0; x < k; x++) { - double xp = x0 + xPos[x] * w; - double yp = y0 + yPos[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::min(std::max(v, 1024), 4095); - samples.push_back(v); - } + return positions; +} + +std::vector LscPolynomialLoader::samplePolynomial(const LscPolynomial &poly) +{ + constexpr int k = RKISP1_CIF_ISP_LSC_SAMPLES_MAX; + + 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 samples; + + ASSERT(xSizes_.size() * 2 + 1 == k); + ASSERT(ySizes_.size() * 2 + 1 == k); + + samples.reserve(k * k); + + std::vector xPos(sizesListToPositions(xSizes_)); + std::vector yPos(sizesListToPositions(ySizes_)); + + for (int y = 0; y < k; y++) { + for (int x = 0; x < k; x++) { + double xp = x0 + xPos[x] * w; + double yp = y0 + yPos[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::min(std::max(v, 1024), 4095); + samples.push_back(v); } - return samples; } - - Size sensorSize_; - Rectangle cropRectangle_; - const std::vector &xSizes_; - const std::vector &ySizes_; -}; + return samples; +} class LscTableLoader { public: int parseLscData(const YamlObject &yamlSets, - std::map &lscData) - { - const auto &sets = yamlSets.asList(); - - for (const auto &yamlSet : sets) { - uint32_t ct = yamlSet["ct"].get(0); - - if (lscData.count(ct)) { - LOG(RkISP1Lsc, Error) - << "Multiple sets found for color temperature " - << ct; - return -EINVAL; - } - - LensShadingCorrection::Components &set = lscData[ct]; - - set.r = parseTable(yamlSet, "r"); - set.gr = parseTable(yamlSet, "gr"); - set.gb = parseTable(yamlSet, "gb"); - set.b = parseTable(yamlSet, "b"); - - if (set.r.empty() || set.gr.empty() || - set.gb.empty() || set.b.empty()) { - LOG(RkISP1Lsc, Error) - << "Set for color temperature " << ct - << " is missing tables"; - return -EINVAL; - } - } + std::map &lscData); + +private: + std::vector parseTable(const YamlObject &tuningData, + const char *prop); +}; + +int LscTableLoader::parseLscData(const YamlObject &yamlSets, + std::map &lscData) +{ + const auto &sets = yamlSets.asList(); + + for (const auto &yamlSet : sets) { + uint32_t ct = yamlSet["ct"].get(0); - if (lscData.empty()) { - LOG(RkISP1Lsc, Error) << "Failed to load any sets"; + if (lscData.count(ct)) { + LOG(RkISP1Lsc, Error) + << "Multiple sets found for color temperature " + << ct; return -EINVAL; } - return 0; - } + LensShadingCorrection::Components &set = lscData[ct]; -private: - std::vector parseTable(const YamlObject &tuningData, - const char *prop) - { - static constexpr unsigned int kLscNumSamples = - RKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX; + set.r = parseTable(yamlSet, "r"); + set.gr = parseTable(yamlSet, "gr"); + set.gb = parseTable(yamlSet, "gb"); + set.b = parseTable(yamlSet, "b"); - std::vector table = - tuningData[prop].getList().value_or(std::vector{}); - if (table.size() != kLscNumSamples) { + if (set.r.empty() || set.gr.empty() || + set.gb.empty() || set.b.empty()) { LOG(RkISP1Lsc, Error) - << "Invalid '" << prop << "' values: expected " - << kLscNumSamples - << " elements, got " << table.size(); - return {}; + << "Set for color temperature " << ct + << " is missing tables"; + return -EINVAL; } + } - return table; + if (lscData.empty()) { + LOG(RkISP1Lsc, Error) << "Failed to load any sets"; + return -EINVAL; } -}; + + return 0; +} + +std::vector LscTableLoader::parseTable(const YamlObject &tuningData, + const char *prop) +{ + static constexpr unsigned int kLscNumSamples = + RKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX; + + std::vector table = + tuningData[prop].getList().value_or(std::vector{}); + if (table.size() != kLscNumSamples) { + LOG(RkISP1Lsc, Error) + << "Invalid '" << prop << "' values: expected " + << kLscNumSamples + << " elements, got " << table.size(); + return {}; + } + + return table; +} static std::vector parseSizes(const YamlObject &tuningData, const char *prop) From patchwork Thu Jan 8 16:05:51 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25698 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 0EDF2BE08B for ; Thu, 8 Jan 2026 16:06:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CD91761FCC; Thu, 8 Jan 2026 17:06:50 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="WwVowVyU"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9C69561FCB for ; Thu, 8 Jan 2026 17:06:49 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 036D463B; Thu, 8 Jan 2026 17:06:26 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888387; bh=kCAMFxdTsXgb/ncye0FF9lUBsIu2F+wdKyikrEvbjTc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=WwVowVyUbROufO5dB+SjvOzCS3BJEN/cLOCuFcvd/Zo4YJYBAtb63rIugXqMA99d/ 2H1knXQzchHuftFQRZJyAW/KM+s1PAy9ya06DDCJdrMmYdcSlfq6pmB3W+eQrnBQm1 ec0tP4+1MzSsQHgcbPK/0FflVnlQeIok/hWvJCxI= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:51 +0100 Subject: [PATCH v2 08/15] ipa: rkisp1: lsc: Move local types into anonymous namespace MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-8-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug X-Mailer: b4 0.14.2 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" Move all local helpers into an anonymous namespace and drop a static modifier that is no longer needed. Signed-off-by: Stefan Klug Reviewed-by: Kieran Bingham Reviewed-by: Barnabás Pőcze --- Changes in v2: - Added this patch --- src/ipa/rkisp1/algorithms/lsc.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 1962d18d148b4abac6e601ec36e0c68944a6191c..c42f74557c7364935254d75ee1fb923d176e0dbd 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -27,8 +27,6 @@ namespace libcamera { namespace ipa { -constexpr int kColourTemperatureChangeThreshhold = 10; - template void interpolateVector(const std::vector &a, const std::vector &b, std::vector &dest, double lambda) @@ -70,6 +68,10 @@ namespace ipa::rkisp1::algorithms { LOG_DEFINE_CATEGORY(RkISP1Lsc) +namespace { + +constexpr int kColourTemperatureChangeThreshhold = 10; + class LscPolynomialLoader { public: @@ -276,8 +278,8 @@ std::vector LscTableLoader::parseTable(const YamlObject &tuningData, return table; } -static std::vector parseSizes(const YamlObject &tuningData, - const char *prop) +std::vector parseSizes(const YamlObject &tuningData, + const char *prop) { std::vector sizes = tuningData[prop].getList().value_or(std::vector{}); @@ -306,6 +308,8 @@ static std::vector parseSizes(const YamlObject &tuningData, return sizes; } +} /* namespace */ + LensShadingCorrection::LensShadingCorrection() : lastAppliedCt_(0), lastAppliedQuantizedCt_(0) { From patchwork Thu Jan 8 16:05:52 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25699 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 B8D28BE08B for ; Thu, 8 Jan 2026 16:06:53 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 82AD661FC7; Thu, 8 Jan 2026 17:06:53 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="K3UFe7u6"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 63F8061FBF for ; Thu, 8 Jan 2026 17:06:52 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id EACB51AEE; Thu, 8 Jan 2026 17:06:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888390; bh=Wa1kb4jis2WTXYoMAut+ajSXm5wP3og7A8V9teDjUgg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=K3UFe7u6CRZlqSxOQRjGpoZABGD6eMghsqFI+VeUAMIuBVNkjsL8Q4fmGQFSRjZRl TqZXFtSlIGpYUXLHw1kNgEIfKdi6ROJFuLr+i3CsXSFDKQmvh0veARzoRzYrZBp2JM qYwELoJU7XAEz83kFAycxdMpVRMcyWMXl2ubiM/w= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:52 +0100 Subject: [PATCH v2 09/15] ipa: rkisp1: lsc: Handle quantization locally MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-9-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug X-Mailer: b4 0.14.2 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 quantization functionality in the Interpolator hinders in writing nice code. Don't use it and implement the functionality directly in the algorithm. This patch doesn't introduce any functional changes. Signed-off-by: Stefan Klug Reviewed-by: Kieran Bingham --- Changes in v2: - Added this patch --- src/ipa/rkisp1/algorithms/lsc.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index c42f74557c7364935254d75ee1fb923d176e0dbd..d5e44021906bda22f16a2c0f2a344e4c40d46774 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -308,12 +308,16 @@ std::vector parseSizes(const YamlObject &tuningData, return sizes; } +static unsigned int quantize(unsigned int value, unsigned int step) +{ + return std::lround(value / static_cast(step)) * step; +} + } /* namespace */ LensShadingCorrection::LensShadingCorrection() : lastAppliedCt_(0), lastAppliedQuantizedCt_(0) { - sets_.setQuantization(kColourTemperatureChangeThreshhold); } /** @@ -426,17 +430,20 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context, RkISP1Params *params) { uint32_t ct = frameContext.awb.temperatureK; - if (std::abs(static_cast(ct) - static_cast(lastAppliedCt_)) < - kColourTemperatureChangeThreshhold) + unsigned int quantizedCt = quantize(ct, kColourTemperatureChangeThreshhold); + int ctDiff = static_cast(ct) - static_cast(lastAppliedCt_); + + if (quantizedCt == lastAppliedQuantizedCt_) return; - unsigned int quantizedCt; - const Components &set = sets_.getInterpolated(ct, &quantizedCt); - if (lastAppliedQuantizedCt_ == quantizedCt) + + if (std::abs(ctDiff) < kColourTemperatureChangeThreshhold) return; auto config = params->block(); config.setEnabled(true); setParameters(*config); + + const Components &set = sets_.getInterpolated(quantizedCt); copyTable(*config, set); lastAppliedCt_ = ct; From patchwork Thu Jan 8 16:05:53 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25700 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 78D8ABE08B for ; Thu, 8 Jan 2026 16:06:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 327C561FD7; Thu, 8 Jan 2026 17:06:57 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="T+KXv0J6"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7560B61FBF for ; Thu, 8 Jan 2026 17:06:55 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 031E81E2F; Thu, 8 Jan 2026 17:06:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888393; bh=+FVHfIXB/1qw3t+vAdo8tVwUJG9X3O4c6QQp6gYctnU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=T+KXv0J6ExBFI+h+lGKoROHdTAOy7NDIO7gnQfgAMxyUX8Uhy1WT9Ph1/5fe4mtHG AkWue8t0Trt5q2tqUukCKmQ+uuaB1wNOT/OhM4XaajMJbNH+WkoGWC7YFWJRbGyoU/ 2P7QSXpm/KkY3cAIXHATv8XAtWtRuTdGzwvkMRR0= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:53 +0100 Subject: [PATCH v2 10/15] ipa: libipa: interpolator: Drop key quantization MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-10-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug X-Mailer: b4 0.14.2 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 quantization of the interpolation key was only used by the LSC algorithm. There it lead to difficult to read code was removed. As there is no remaining user of it, drop it from the Interpolator class. While at it, cleanup the includes. Signed-off-by: Stefan Klug Signed-off-by: Stefan Klug Reviewed-by: Kieran Bingham Reviewed-by: Barnabás Pőcze --- Changes in v2: - Added this patch --- src/ipa/libipa/interpolator.cpp | 25 +------------------------ src/ipa/libipa/interpolator.h | 14 +------------- test/ipa/libipa/interpolator.cpp | 7 ------- 3 files changed, 2 insertions(+), 44 deletions(-) diff --git a/src/ipa/libipa/interpolator.cpp b/src/ipa/libipa/interpolator.cpp index f901a86e4c74db6708a61e5491aa68f231e4a318..00bf66b6c2af3ce2cd9a94d5e02290c14fa3ba50 100644 --- a/src/ipa/libipa/interpolator.cpp +++ b/src/ipa/libipa/interpolator.cpp @@ -6,15 +6,8 @@ */ #include "interpolator.h" -#include -#include - #include -#include "libcamera/internal/yaml_parser.h" - -#include "interpolator.h" - /** * \file interpolator.h * \brief Helper class for linear interpolating a set of objects @@ -104,20 +97,6 @@ namespace ipa { * \return Zero on success, negative error code otherwise */ -/** - * \fn void Interpolator::setQuantization(const unsigned int q) - * \brief Set the quantization value - * \param[in] q The quantization value - * - * Sets the quantization value. When this is set, 'key' gets quantized to this - * size, before doing the interpolation. This can help in reducing the number of - * updates pushed to the hardware. - * - * Note that normally a threshold needs to be combined with quantization. - * Otherwise a value that swings around the edge of the quantization step will - * lead to constant updates. - */ - /** * \fn void Interpolator::setData(std::map &&data) * \brief Set the internal map @@ -136,10 +115,8 @@ namespace ipa { * \fn const T& Interpolator::getInterpolated() * \brief Retrieve an interpolated value for the given key * \param[in] key The unsigned integer key of the object to retrieve - * \param[out] quantizedKey If provided, the key value after quantization * \return The object corresponding to the key. The object is cached internally, - * so on successive calls with the same key (after quantization) interpolation - * is not recalculated. + * so on successive calls with the same key interpolation is not recalculated. */ /** diff --git a/src/ipa/libipa/interpolator.h b/src/ipa/libipa/interpolator.h index 7880db6976d15aa033678f4aeb4934f5cd785bd9..fb2c611d186ed2bc8a733bdbb4273fca47942565 100644 --- a/src/ipa/libipa/interpolator.h +++ b/src/ipa/libipa/interpolator.h @@ -70,11 +70,6 @@ public: return 0; } - void setQuantization(const unsigned int q) - { - quantization_ = q; - } - void setData(std::map &&data) { data_ = std::move(data); @@ -86,16 +81,10 @@ public: return data_; } - const T &getInterpolated(unsigned int key, unsigned int *quantizedKey = nullptr) + const T &getInterpolated(unsigned int key) { ASSERT(data_.size() > 0); - if (quantization_ > 0) - key = std::lround(key / static_cast(quantization_)) * quantization_; - - if (quantizedKey) - *quantizedKey = key; - if (lastInterpolatedKey_.has_value() && *lastInterpolatedKey_ == key) return lastInterpolatedValue_; @@ -128,7 +117,6 @@ private: std::map data_; T lastInterpolatedValue_; std::optional lastInterpolatedKey_; - unsigned int quantization_ = 0; }; } /* namespace ipa */ diff --git a/test/ipa/libipa/interpolator.cpp b/test/ipa/libipa/interpolator.cpp index 6abb776060d43b8339cf9b632cac1806a9c5f9b0..03b7089a7a05fb1a2b6ee568ad8e92ad7ac716ee 100644 --- a/test/ipa/libipa/interpolator.cpp +++ b/test/ipa/libipa/interpolator.cpp @@ -40,13 +40,6 @@ protected: ASSERT_EQ(interpolator.getInterpolated(30), 300); ASSERT_EQ(interpolator.getInterpolated(40), 300); - interpolator.setQuantization(10); - unsigned int q = 0; - ASSERT_EQ(interpolator.getInterpolated(25, &q), 300); - ASSERT_EQ(q, 30); - ASSERT_EQ(interpolator.getInterpolated(24, &q), 200); - ASSERT_EQ(q, 20); - return TestPass; } }; From patchwork Thu Jan 8 16:05:54 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25701 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 3A893BE08B for ; Thu, 8 Jan 2026 16:07:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E3E9361FD2; Thu, 8 Jan 2026 17:06:59 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="VCEsf4Kf"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3A83861FC5 for ; Thu, 8 Jan 2026 17:06:58 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id B950D1C7B; Thu, 8 Jan 2026 17:06:35 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888395; bh=JrytFhMU5YU+EmGYdpqVpmagZjb7v8qmQ66VIVL3qbs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=VCEsf4Kfj7UOP27l6E4c1jwa/yk1ZLcyhp8SX2l/xHheGt0kj8RB7PCvNRpdeysC2 +fDuOOnYNgTYOrFrCowtNma6SxrHWLOkk5i+pFa5DvJf8FY4cORbXtVk5nNOsErEpM bJVIO+I+xocdU3FLg1ykUUNq4bfDM6YYtOrp3Z58= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:54 +0100 Subject: [PATCH v2 11/15] ipa: rkisp1: lsc: Pass sampling positions into samplePolynomial MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-11-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , Laurent Pinchart X-Mailer: b4 0.14.2 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" There is no need to recalculate the sampling positions over and over. Pass them as parameter into the sampling function. The vectors are still kept inside the loop as this is also a preparatory change for the upcoming refactoring. Signed-off-by: Stefan Klug Reviewed-by: Barnabás Pőcze Reviewed-by: Laurent Pinchart --- Changes in v2: - Small fixes from review: - Replaced move construction by move assignments - Replaced some vectors by Spans - Collected tags --- src/ipa/rkisp1/algorithms/lsc.cpp | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index d5e44021906bda22f16a2c0f2a344e4c40d46774..7505307bfbaa02710b36b47d00d88a582886c1c0 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -91,7 +91,9 @@ public: private: std::vector sizesListToPositions(const std::vector &sizes); - std::vector samplePolynomial(const LscPolynomial &poly); + std::vector samplePolynomial(const LscPolynomial &poly, + Span xPositions, + Span yPositions); Size sensorSize_; Rectangle cropRectangle_; @@ -131,10 +133,13 @@ int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, pgr->setReferenceImageSize(sensorSize_); pgb->setReferenceImageSize(sensorSize_); pb->setReferenceImageSize(sensorSize_); - set.r = samplePolynomial(*pr); - set.gr = samplePolynomial(*pgr); - set.gb = samplePolynomial(*pgb); - set.b = samplePolynomial(*pb); + + std::vector xPos = sizesListToPositions(xSizes_); + std::vector yPos = sizesListToPositions(ySizes_); + set.r = samplePolynomial(*pr, xPos, yPos); + set.gr = samplePolynomial(*pgr, xPos, yPos); + set.gb = samplePolynomial(*pgb, xPos, yPos); + set.b = samplePolynomial(*pb, xPos, yPos); } if (lscData.empty()) { @@ -171,10 +176,10 @@ std::vector LscPolynomialLoader::sizesListToPositions(const std::vector< return positions; } -std::vector LscPolynomialLoader::samplePolynomial(const LscPolynomial &poly) +std::vector LscPolynomialLoader::samplePolynomial(const LscPolynomial &poly, + Span xPositions, + Span yPositions) { - constexpr int k = RKISP1_CIF_ISP_LSC_SAMPLES_MAX; - double m = poly.getM(); double x0 = cropRectangle_.x / m; double y0 = cropRectangle_.y / m; @@ -182,18 +187,12 @@ std::vector LscPolynomialLoader::samplePolynomial(const LscPolynomial double h = cropRectangle_.height / m; std::vector samples; - ASSERT(xSizes_.size() * 2 + 1 == k); - ASSERT(ySizes_.size() * 2 + 1 == k); - - samples.reserve(k * k); - - std::vector xPos(sizesListToPositions(xSizes_)); - std::vector yPos(sizesListToPositions(ySizes_)); + samples.reserve(xPositions.size() * yPositions.size()); - for (int y = 0; y < k; y++) { - for (int x = 0; x < k; x++) { - double xp = x0 + xPos[x] * w; - double yp = y0 + yPos[y] * h; + 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 From patchwork Thu Jan 8 16:05:55 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25702 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 B2F56BE08B for ; Thu, 8 Jan 2026 16:07:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7AD3E61FC7; Thu, 8 Jan 2026 17:07:03 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="RvrBngdi"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4DE7561FC5 for ; Thu, 8 Jan 2026 17:07:01 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 9BE6F1E2F; Thu, 8 Jan 2026 17:06:38 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888398; bh=6DcFU41nFTZ+ryNzV+MHGZvgRGDJ2yf8ftNYclk/8WQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=RvrBngdiWxv4kP/NZauZ8ZyeZw8K9GJfiw9VOcEK0kSxEVZbejPymV08TmXcnbXyX OKaBE4o1WtGH/2COb+x0jv9xVTZ7zWAeEa6WUgwpaVrZZUe3S9Uc7mlJcrLhuWJrNf 6+egPmPV5mbuC9WY7cN9OTFMUNl1bCTvZg6PRF/U= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:55 +0100 Subject: [PATCH v2 12/15] ipa: rkisp1: lsc: Pass crop rectangle as parameter MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-12-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , Rui Wang X-Mailer: b4 0.14.2 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" In preparation for the upcoming rework, pass the crop rectangle as parameter to samplePolynomial(). This patch contains no functional change. Signed-off-by: Stefan Klug Reviewed-by: Barnabás Pőcze Reviewed-by: Rui Wang --- Changes in v2: - Collected tags --- src/ipa/rkisp1/algorithms/lsc.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 7505307bfbaa02710b36b47d00d88a582886c1c0..a5855f8a0a67a6b5ad95635454f3716d07c86e6f 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -93,7 +93,8 @@ private: std::vector sizesListToPositions(const std::vector &sizes); std::vector samplePolynomial(const LscPolynomial &poly, Span xPositions, - Span yPositions); + Span yPositions, + const Rectangle &cropRectangle); Size sensorSize_; Rectangle cropRectangle_; @@ -136,10 +137,10 @@ int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, std::vector xPos = sizesListToPositions(xSizes_); std::vector yPos = sizesListToPositions(ySizes_); - set.r = samplePolynomial(*pr, xPos, yPos); - set.gr = samplePolynomial(*pgr, xPos, yPos); - set.gb = samplePolynomial(*pgb, xPos, yPos); - set.b = samplePolynomial(*pb, xPos, yPos); + 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()) { @@ -178,13 +179,14 @@ std::vector LscPolynomialLoader::sizesListToPositions(const std::vector< std::vector LscPolynomialLoader::samplePolynomial(const LscPolynomial &poly, Span xPositions, - Span yPositions) + Span 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; + double x0 = cropRectangle.x / m; + double y0 = cropRectangle.y / m; + double w = cropRectangle.width / m; + double h = cropRectangle.height / m; std::vector samples; samples.reserve(xPositions.size() * yPositions.size()); From patchwork Thu Jan 8 16:05:56 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25703 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 53488BE08B for ; Thu, 8 Jan 2026 16:07:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0496461FDE; Thu, 8 Jan 2026 17:07:06 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="HmkYpdcH"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BBBD961FC5 for ; Thu, 8 Jan 2026 17:07:04 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 1BF5326D2; Thu, 8 Jan 2026 17:06:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888402; bh=rsFrVOVU+1EDCj1TbjsOHC9KGpb7qZR65YvDwV3jm6I=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=HmkYpdcHA9gxx6Eu9ZEn49ghGLVmznibieWa/nV+eT8ub4Wb5wd6bKqLFZkB9xR/l iEpFvHqVWt9ntyA8BIqxlbQZTuwPtlwhXu1eeOMa7MilZp5OHzX4xe6WWN/xekcM5h AsPXEmSSuTPlBdI5UIdNqUuL/soQJb/OdjQI90k0= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:56 +0100 Subject: [PATCH v2 13/15] ipa: rkisp1: lsc: Resample polynomial lens shading tables at configure time MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-13-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug X-Mailer: b4 0.14.2 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 lens shading correction is always applied based on the sensor crop bounds. This leads to incorrect lens shading correction for analog crops that do not cover the whole sensor. To fix that, we need to adapt the lens shading table for the selected analog crop at configure time. Introduce an abstract ShadingDescriptor class that holds the lens shading information that can then be sampled at configure time for a specific crop rectangle. Resampling for a specific crop is only implemented for polynomial lsc data. For tabular data, a warning is logged and the unmodified table is returned. This matches the current functionality for tabular data and is a huge improvement for polynomial data. Signed-off-by: Stefan Klug --- Changes in v2: - Replaced "auto const" by "const auto" - Replaces some vector parameters by Spans - Changed sampleForCrop to return the components - Replaced min/max by clamp - Replaced map.swap() by move assignment --- src/ipa/rkisp1/algorithms/lsc.cpp | 233 ++++++++++++++++++++++++-------------- src/ipa/rkisp1/algorithms/lsc.h | 13 +++ 2 files changed, 159 insertions(+), 87 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index a5855f8a0a67a6b5ad95635454f3716d07c86e6f..698f07b85bfa5d3de0c454087bf8e0874d85add7 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -72,38 +72,127 @@ namespace { constexpr int kColourTemperatureChangeThreshhold = 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); + std::vector sizesListToPositions(Span sizes); + + LscPolynomial pr_; + LscPolynomial pgr_; + LscPolynomial pgb_; + LscPolynomial pb_; +}; + +LensShadingCorrection::Components +LscPolynomialShadingDescriptor::sampleForCrop(const Rectangle &cropRectangle, + Span xSizes, + Span ySizes) +{ + std::vector xPos = sizesListToPositions(xSizes); + std::vector 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 +LscPolynomialShadingDescriptor::samplePolynomial(const LscPolynomial &poly, + Span xPositions, + Span 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 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( + 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 +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_; - Rectangle cropRectangle_; - const std::vector &xSizes_; - const std::vector &ySizes_; }; int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, - std::map &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(); pgr = yamlSet["gr"].get(); pgb = yamlSet["gb"].get(); @@ -135,12 +223,9 @@ int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets, 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_); + lscData.emplace( + ct, std::make_unique( + *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 LscPolynomialLoader::sizesListToPositions(const std::vector &sizes) +class LscTableShadingDescriptor : public LensShadingCorrection::ShadingDescriptor { - 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; +public: + LscTableShadingDescriptor(LensShadingCorrection::Components components) + : lscData_(std::move(components)) + { } - return positions; -} - -std::vector LscPolynomialLoader::samplePolynomial(const LscPolynomial &poly, - Span xPositions, - Span 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 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( - 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 xSizes, + [[maybe_unused]] Span ySizes) + { + 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 &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 7b68dda1a0d4257c345e0f1b77aa498f8183c92f..3097740a6cb2ce9063a4ba087856987a489b0ab6 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_; From patchwork Thu Jan 8 16:05:57 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25704 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 DADC0BE08B for ; Thu, 8 Jan 2026 16:07:09 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8869961FD2; Thu, 8 Jan 2026 17:07:09 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="e3fMUlEM"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 365BF61FD2 for ; Thu, 8 Jan 2026 17:07:07 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id B959719D0; Thu, 8 Jan 2026 17:06:44 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888404; bh=l2OgRVSM0AY54TpUR6RuzVrXqx/vDN2aZdAVq0yhDzQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=e3fMUlEMCbvSYuDs4k9BPahUYKCZY9OSDjekwddZ2LpZYkwCQzFgwq3ir7bWenrPX h4hB8SZZwaNW4bbD0WPW+K1UfJLCbCnFY4NuNO0U0scTC7MUAb8usZt8XLETq/Z3DV rZ3IEjbJaQV0i77zFTNTHwCl7+SyGRMHMlbSGDX4= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:57 +0100 Subject: [PATCH v2 14/15] libcamera: control_ids: Introduce LensShadingCorrectionEnable MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-14-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , Jacopo Mondi X-Mailer: b4 0.14.2 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" Introduce a control to enable and disable LSC and replace the draft android control. Having a map as in andoid doesn't give a benefit as up to today no values apart from ON/OFF were ever implemented. Signed-off-by: Jacopo Mondi Signed-off-by: Stefan Klug --- Changes in v2: - Renamed LensShadingEnable to LensShadingCorrectionEnable - Fixed android code to properly handle the boolean value - Added "only if tuned" info sentence to the control description --- src/android/camera_capabilities.cpp | 11 ++++------- src/libcamera/control_ids_core.yaml | 9 +++++++++ src/libcamera/control_ids_draft.yaml | 14 -------------- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp index b161bc6b3ed68b7206e524762f8a941816812e45..9948868d3bd99a9cfb59a5d48a20ccc455a94964 100644 --- a/src/android/camera_capabilities.cpp +++ b/src/android/camera_capabilities.cpp @@ -1223,13 +1223,10 @@ int CameraCapabilities::initializeStaticMetadata() { std::vector data; data.reserve(2); - const auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode); - if (infoMap != controlsInfo.end()) { - for (const auto &value : infoMap->second.values()) - data.push_back(value.get()); - } else { - data.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF); - } + data.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF); + const auto &infoMap = controlsInfo.find(&controls::LensShadingCorrectionEnable); + if (infoMap != controlsInfo.end()) + data.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON); staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, data); } diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml index 8e99bd84825f6060dbc323be3f4b0cd6283e0942..ced98e4625bfba9165be4f93d1fd2756881a2d1b 100644 --- a/src/libcamera/control_ids_core.yaml +++ b/src/libcamera/control_ids_core.yaml @@ -1356,4 +1356,13 @@ controls: Enable or disable lens dewarping. This control is only available if lens dewarp parameters are configured in the tuning file. + - LensShadingCorrectionEnable: + type: bool + direction: inout + description: | + Enable or disable the lens shading algorithm. + + This control is only available when there are valid lens shading + correction parameters available in the tuning file. + ... diff --git a/src/libcamera/control_ids_draft.yaml b/src/libcamera/control_ids_draft.yaml index 03309eeac34fa76eee4bb5d1c87d6467b890c9a7..14026de46ad6de92cfd978e5c68c9944ce9987fa 100644 --- a/src/libcamera/control_ids_draft.yaml +++ b/src/libcamera/control_ids_draft.yaml @@ -110,20 +110,6 @@ controls: row and the start of exposure of the last row. Currently identical to ANDROID_SENSOR_ROLLING_SHUTTER_SKEW - - LensShadingMapMode: - type: int32_t - direction: inout - description: | - Control to report if the lens shading map is available. Currently - identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. - enum: - - name: LensShadingMapModeOff - value: 0 - description: No lens shading map mode is available. - - name: LensShadingMapModeOn - value: 1 - description: The lens shading map mode is available. - - PipelineDepth: type: int32_t direction: out From patchwork Thu Jan 8 16:05:58 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25705 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 62335BE08B for ; Thu, 8 Jan 2026 16:07:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 27B2861FBB; Thu, 8 Jan 2026 17:07:11 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="pxffyVRb"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BA1FC61FDA for ; Thu, 8 Jan 2026 17:07:09 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:90af:8957:b721:10d4]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 49FDF19D0; Thu, 8 Jan 2026 17:06:47 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1767888407; bh=/HR/SVEGTjbt6VZVxVy4iJ9xGipIwjEVZ2Gf9+OoblE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=pxffyVRb3vrir/mF2VfFrTyHL0gs9YhToYJnrYT/4xXO7DNyJBn44zpTdf0vf1zyz tS9XHbLsHEOSXShxKc/yyr+A1ozwSQ2QAp5GnkkcsTVJxq7Ui2BTedyskS7pqfVDKs GB3qLVWHNgK4p9nw40wagnysswCNTNt71EU8FLkQ= From: Stefan Klug Date: Thu, 08 Jan 2026 17:05:58 +0100 Subject: [PATCH v2 15/15] ipa: rkisp1: Implement LensShadingCorrectionEnable control MIME-Version: 1.0 Message-Id: <20260108-sklug-lsc-resampling-v2-dev-v2-15-e682ec4b9893@ideasonboard.com> References: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> In-Reply-To: <20260108-sklug-lsc-resampling-v2-dev-v2-0-e682ec4b9893@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug X-Mailer: b4 0.14.2 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" Implement the LensShadingCorrectionEnable control for rkisp1. Signed-off-by: Stefan Klug Tested-by: Barnabás Pőcze --- Changes in v2: - Add the control only if LSC is properly configured in the tuning file - Introduce enable flag in frame context for per frame control --- src/ipa/rkisp1/algorithms/dpf.cpp | 2 +- src/ipa/rkisp1/algorithms/lsc.cpp | 48 ++++++++++++++++++++++++++++++++++----- src/ipa/rkisp1/algorithms/lsc.h | 3 +++ src/ipa/rkisp1/ipa_context.h | 13 +++++++---- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 39f3e461f313dfbf35cb5d6a0daca0540bdf7b6b..83c1e4b7b355041295cbe0498a8dd70877ea6636 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -233,7 +233,7 @@ void Dpf::prepare(IPAContext &context, const uint32_t frame, *strengthConfig = strengthConfig_; const auto &awb = context.configuration.awb; - const auto &lsc = context.configuration.lsc; + const auto &lsc = context.activeState.lsc; auto &mode = config->gain.mode; diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 698f07b85bfa5d3de0c454087bf8e0874d85add7..cb3f8550457eb2e67959ce034d037ac60328d267 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -416,6 +416,8 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, if (ret) return ret; + context.ctrlMap[&controls::LensShadingCorrectionEnable] = ControlInfo(false, true, true); + shadingDescriptors_ = std::move(lscData); return 0; @@ -460,7 +462,7 @@ int LensShadingCorrection::configure(IPAContext &context, sets_.setData(std::move(shadingData)); - context.configuration.lsc.enabled = true; + context.activeState.lsc.enabled = true; return 0; } @@ -481,6 +483,29 @@ void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config, std::copy(set.b.begin(), set.b.end(), &config.b_data_tbl[0][0]); } +/** + * \copydoc libcamera::ipa::Algorithm::queueRequest + */ +void LensShadingCorrection::queueRequest(IPAContext &context, + [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, + const ControlList &controls) +{ + auto &lsc = context.activeState.lsc; + + const auto &lscEnable = controls.get(controls::LensShadingCorrectionEnable); + if (lscEnable && *lscEnable != lsc.enabled) { + lsc.enabled = *lscEnable; + + LOG(RkISP1Lsc, Debug) + << (*lscEnable ? "Enabling" : "Disabling") << " Lsc"; + + frameContext.lsc.update = true; + } + + frameContext.lsc.enabled = lsc.enabled; +} + /** * \copydoc libcamera::ipa::Algorithm::prepare */ @@ -493,14 +518,25 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context, unsigned int quantizedCt = quantize(ct, kColourTemperatureChangeThreshhold); int ctDiff = static_cast(ct) - static_cast(lastAppliedCt_); - if (quantizedCt == lastAppliedQuantizedCt_) - return; - if (std::abs(ctDiff) < kColourTemperatureChangeThreshhold) - return; + /* Check if we can skip the update. */ + if (!frameContext.lsc.update) { + if (!frameContext.lsc.enabled) + return; + + if (quantizedCt == lastAppliedQuantizedCt_) + return; + + if (std::abs(ctDiff) < kColourTemperatureChangeThreshhold) + return; + } auto config = params->block(); - config.setEnabled(true); + config.setEnabled(frameContext.lsc.enabled); + + if (!frameContext.lsc.enabled) + return; + setParameters(*config); const Components &set = sets_.getInterpolated(quantizedCt); diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h index 3097740a6cb2ce9063a4ba087856987a489b0ab6..ff4e8d91fe87d99b6dae8d611afc23846081bcd5 100644 --- a/src/ipa/rkisp1/algorithms/lsc.h +++ b/src/ipa/rkisp1/algorithms/lsc.h @@ -29,6 +29,9 @@ public: void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) override; + void queueRequest(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + const ControlList &controls) override; struct Components { std::vector r; diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h index b257cee55379ad932b42e613f94eccbe69a939e3..fa748811be743b43ce6ee289408c054c6f9a7046 100644 --- a/src/ipa/rkisp1/ipa_context.h +++ b/src/ipa/rkisp1/ipa_context.h @@ -55,10 +55,6 @@ struct IPASessionConfiguration { bool supported; } compress; - struct { - bool enabled; - } lsc; - struct { utils::Duration minExposureTime; utils::Duration maxExposureTime; @@ -143,6 +139,10 @@ struct IPAActiveState { double gain; double strength; } wdr; + + struct { + bool enabled; + } lsc; }; struct IPAFrameContext : public FrameContext { @@ -218,6 +218,11 @@ struct IPAFrameContext : public FrameContext { double strength; double gain; } wdr; + + struct { + bool enabled; + bool update; + } lsc; }; struct IPAContext {