From patchwork Wed Jan 14 11:57: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: 25781 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 BCFA8C3226 for ; Wed, 14 Jan 2026 11:58:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 67E2A61FB9; Wed, 14 Jan 2026 12:58:05 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Nt7CmJv3"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B3D3861FA3 for ; Wed, 14 Jan 2026 12:58:03 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 064D64BB; Wed, 14 Jan 2026 12:57:36 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391857; bh=OcEp1RGR9Yo43utM4YX0sN8zvzSy2va566Bm6G86NKo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Nt7CmJv3k21o26sF6q7w7MGAE88UHS0RJM0Wz/kyMzRTbY6TK+ayBXS/Zu3W8I+i7 wHZn05aAYlUBfES1znJK246UpTTXbItI0yAhH2pk4ggU1EBF8GHYwtL+/I35MgoSNV TzN0RxNXGVgyz2jKC4e/nmlw9x5qjobd52Q0S02c= From: Stefan Klug Date: Wed, 14 Jan 2026 12:57:54 +0100 Subject: [PATCH v3 01/15] ipa: rkisp1: lsc: Drop unused member variable MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-1-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@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 Wed Jan 14 11:57: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: 25782 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 4077FC3226 for ; Wed, 14 Jan 2026 11:58:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id F3B8661FC2; Wed, 14 Jan 2026 12:58:07 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="rIYf4RTS"; 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 26CA061FA3 for ; Wed, 14 Jan 2026 12:58:06 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 7B70F316; Wed, 14 Jan 2026 12:57:39 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391859; bh=H02CYr/W/mR0vOF0IrXmTD9xh4WEHezABJY6Jg+EPvo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=rIYf4RTS9PhXn3LzODEyCbyv7WGHrHa2+e5BlATxh5nRmbLWAOIjcbp/iai/Kt4ks Yd33iAIN7F9t9L6dP92J1UoiMuTkTvZVQpOqBahKRQHzZnVkDhFHSAKmEl+920pPFW UgshXTUm16jhrxDL1rAnn+feCXPFWgvPWkLkruQw= From: Stefan Klug Date: Wed, 14 Jan 2026 12:57:55 +0100 Subject: [PATCH v3 02/15] ipa: rkisp1: lsc: Drop unused function declaration MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-2-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@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 Wed Jan 14 11:57:56 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25783 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 1E235C3226 for ; Wed, 14 Jan 2026 11:58:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CE51B61FC1; Wed, 14 Jan 2026 12:58:10 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="va106RFw"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6AA0461FA3 for ; Wed, 14 Jan 2026 12:58:09 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id BA78D6A8; Wed, 14 Jan 2026 12:57:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391862; bh=XclvvXKia3KXTQl/qKvBdoELOBtaOgq+NkY74Ldf5HU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=va106RFweLHg3kQoCIzPWihQIzeu/EOf3+OsrbEob/Mk9adrRg3rRGQTJaYbTTiQl sEAAdsdDPcV2Ny94C8v6aw0/b81XM0s+KedK4SKoNsZPBTjvdQp9/RtIPyNeSqr/UC Xs+YiRiGkdAH2mxsXsp/4O1dewowQTN8EGBl0n0o= From: Stefan Klug Date: Wed, 14 Jan 2026 12:57:56 +0100 Subject: [PATCH v3 03/15] ipa: rkisp1: lsc: Replace assert with ASSERT MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-3-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@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 Wed Jan 14 11:57:57 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25784 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 2C4E4C3226 for ; Wed, 14 Jan 2026 11:58:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DDDDB61FCC; Wed, 14 Jan 2026 12:58:12 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Wjer7xps"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E6FF261FA3 for ; Wed, 14 Jan 2026 12:58:11 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 0DAC8316; Wed, 14 Jan 2026 12:57:45 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391865; bh=OidrM49Hyx9J+ESnrJB6SegC1GcDkuwWcSVuhdfK2Uc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Wjer7xpsM7JuhC2anZW250AXUCIwnLLWJh0yvbloFenaG6p8BbWKIHV7ZSD2g5YHn Igglser+eZFy+6+q9NhrcyhxRRPoP5fFxNnz+dT++7axCzOS7atCA5BAkhGnVh34Ic X1KO5b3AciZeaG+vpbrZl+OS7E6U9i7r1In7brEA= From: Stefan Klug Date: Wed, 14 Jan 2026 12:57:57 +0100 Subject: [PATCH v3 04/15] ipa: rkisp1: lsc: Rename res to positions MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-4-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@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 Wed Jan 14 11:57: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: 25785 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 DC5B4C3226 for ; Wed, 14 Jan 2026 11:58:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 92E8B61FB9; Wed, 14 Jan 2026 12:58:16 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="q2yPPNrj"; 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 A08CA61FB9 for ; Wed, 14 Jan 2026 12:58:14 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id EF84B6A8; Wed, 14 Jan 2026 12:57:47 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391868; bh=Q66L+qBP3d9HUh5DEB9HQOwvALS5AmnZ9rrQY4rui1k=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=q2yPPNrjn+F4hL6HrSlcUs2kWakTLvlR+5Jcyy3vmvsN1Dsq94+3xIka7OwObbAch H1Iz4PXbGCgex9yVyyW++ZPA6lvudag503AgXo7HuNWn2HNbLKya29yUPD10d/Yj5y WnOGyCiK+TnnSDgdLPagjjCq4NW7mASTcmKzMlQk= From: Stefan Klug Date: Wed, 14 Jan 2026 12:57:58 +0100 Subject: [PATCH v3 05/15] ipa: rkisp1: lsc: Rename res to ret MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-5-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@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 Wed Jan 14 11:57:59 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25786 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 7744EC3274 for ; Wed, 14 Jan 2026 11:58:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 172C661FC8; Wed, 14 Jan 2026 12:58:18 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Bo9KuEYA"; 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 CC17C61FC5 for ; Wed, 14 Jan 2026 12:58:16 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id E7C0F4BB; Wed, 14 Jan 2026 12:57:49 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391870; bh=jpVW171WvOTT4/C/X32xZQLYDdf8/dod1BqJw5h2R6g=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Bo9KuEYAu8qAOq/4i6mpTUkAu564Z5QGwS5qedvgC6L8YcikdEsjZkGTqYyQY7BaN dIyNTH5UnGm5pUR81R1gW/Y3/J6D67Dw5g8BtqcC2yTav2P2YmUS/IVgYcNVmTZoyX oY9+1wiX+cv+fzOyi9P5Lln9QEIaHp5cQxBGfi9Y= From: Stefan Klug Date: Wed, 14 Jan 2026 12:57:59 +0100 Subject: [PATCH v3 06/15] ipa: rkisp1: lsc: Rename res to samples MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-6-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@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 Wed Jan 14 11:58:00 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25787 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 DDAA3C3226 for ; Wed, 14 Jan 2026 11:58:21 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9282161FC1; Wed, 14 Jan 2026 12:58:21 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="TSVOv5HP"; 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 D194D61FB9 for ; Wed, 14 Jan 2026 12:58:19 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 1F3914BB; Wed, 14 Jan 2026 12:57:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391873; bh=FZ8GonHX/9GBtesyrRJ6bQHXD74/oO2vTKfx8iChULw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=TSVOv5HP/WWFuBWoS/GVl/NxJy6Y9ozkY0JK5byZIliFIw3dWF/Subgki5o+Ntny+ DXh3eihfjzeoh+FbUxk6vmrENG/4utmN0GRcoI8kHgAXzhdLZFmc2VzgU5cq2aHrGL CcyoHhpnWSa4FbjDDuKR4fzOJlb/gfCJpCH6UTWw= From: Stefan Klug Date: Wed, 14 Jan 2026 12:58:00 +0100 Subject: [PATCH v3 07/15] ipa: rksip1: lsc: Move function definitions out of class MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-7-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@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 Wed Jan 14 11:58:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25788 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 60F7AC3226 for ; Wed, 14 Jan 2026 11:58:24 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1328461FD0; Wed, 14 Jan 2026 12:58:24 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="mWJflsiw"; 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 E1B9861FB9 for ; Wed, 14 Jan 2026 12:58:22 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 36A59316; Wed, 14 Jan 2026 12:57:56 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391876; bh=0l6JnCw672jvY9tLeKTKm0Y+MPFLCOZ2jHu4Q8BNJ4o=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=mWJflsiw/jWirn0g7hqIRR6uO32eoFRy0gUR8iYCdVpqYoe9Cy7NZuA1AoCchgkFH xZRhi5NOmddOftzkiTPwZsr5e/oy6aVbEO+ooU4ci7DvG/Mq/Y/0rk91ZThmTAFUgQ qLxBD7uYiuTdHTDgv1OqD/kraAaHUG2SUSlqSCw0= From: Stefan Klug Date: Wed, 14 Jan 2026 12:58:01 +0100 Subject: [PATCH v3 08/15] ipa: rkisp1: lsc: Move local types into anonymous namespace MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-8-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= 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 v3: - Collected tags 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 Wed Jan 14 11:58:02 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25789 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 10626C3226 for ; Wed, 14 Jan 2026 11:58:28 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B9B9F61FCF; Wed, 14 Jan 2026 12:58:27 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Rw1I3Vct"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B1B4C61FB9 for ; Wed, 14 Jan 2026 12:58:25 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 0790F316; Wed, 14 Jan 2026 12:57:59 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391879; bh=Roq0HS8t5ZHiOGNOCWixxddzZZncwjZ5zGsFl752i7A=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Rw1I3Vct58g+DNbc79XYV/1P99Hh8IeluygvUbYmkWL2Bxm1R3zz6zAleuu/ey6+u xx6SKEO3ITc0C0QveZ5ItAdZ/0y5zpyGp3sZBDWCEC5W4ED1ii9+8J0q/nDyrw5s+l TU/a2eJrnTvzJdjdZY3wExDQhdsVsfsKcism98BY= From: Stefan Klug Date: Wed, 14 Jan 2026 12:58:02 +0100 Subject: [PATCH v3 09/15] ipa: rkisp1: lsc: Handle quantization locally MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-9-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , Kieran Bingham 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. While at it, reduce the threshold to half of the quantization step size, otherwise it might happen that we skip a full quantization step. Rename the kColourTemperatureChangeThreshhold to kColourTemperatureQuantization to better express the usecase. Signed-off-by: Stefan Klug Reviewed-by: Kieran Bingham Reviewed-by: Barnabás Pőcze --- Changes in v3: - Reduce threshold to quantization step/2 - Drop unnecessary static modifier - Collected tag Changes in v2: - Added this patch --- src/ipa/rkisp1/algorithms/lsc.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index c42f74557c7364935254d75ee1fb923d176e0dbd..77ed0a95209ac13e82f4ee43f7a22095bb5fd65f 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -70,7 +70,7 @@ LOG_DEFINE_CATEGORY(RkISP1Lsc) namespace { -constexpr int kColourTemperatureChangeThreshhold = 10; +constexpr int kColourTemperatureQuantization = 10; class LscPolynomialLoader { @@ -308,12 +308,16 @@ std::vector parseSizes(const YamlObject &tuningData, return sizes; } +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,24 @@ 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, kColourTemperatureQuantization); + int ctDiff = static_cast(ct) - static_cast(lastAppliedCt_); + + /* + * Add a threshold so that oscillations around a quantization step don't + * lead to constant changes. + */ + if (std::abs(ctDiff) < kColourTemperatureQuantization / 2) return; - unsigned int quantizedCt; - const Components &set = sets_.getInterpolated(ct, &quantizedCt); - if (lastAppliedQuantizedCt_ == quantizedCt) + + if (quantizedCt == lastAppliedQuantizedCt_) return; auto config = params->block(); config.setEnabled(true); setParameters(*config); + + const Components &set = sets_.getInterpolated(quantizedCt); copyTable(*config, set); lastAppliedCt_ = ct; From patchwork Wed Jan 14 11:58:03 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25790 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 8C027C3226 for ; Wed, 14 Jan 2026 11:58:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 52B9C61FD8; Wed, 14 Jan 2026 12:58:30 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="LsIgyXlQ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E699B61FC1 for ; Wed, 14 Jan 2026 12:58:28 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 3BFD26A8; Wed, 14 Jan 2026 12:58:02 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391882; bh=MOI5N6IRma7MhEbzHhWpvQFpFqWsD3F/bk/CxbcJ024=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=LsIgyXlQfq9qzR5RrvfO9y+Dh2YqkAMiETjhsMBXqc8zRTs0ndg9jFBydn7KzG5bQ GHZUgelz+JVPxMZtEcdkpCHa8O8Id8DxqiiR7S/ptBFMWUshoRSE/7evxt9f3VQ9Ef qUsJP7YLWKOs88WVuSEo6tLsEMV3MQOY9hguzdmU= From: Stefan Klug Date: Wed, 14 Jan 2026 12:58:03 +0100 Subject: [PATCH v3 10/15] ipa: libipa: interpolator: Drop key quantization MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-10-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= 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 Reviewed-by: Kieran Bingham Reviewed-by: Barnabás Pőcze --- Changes in v3: - Collected tags 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 Wed Jan 14 11:58:04 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25791 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 27DDAC3226 for ; Wed, 14 Jan 2026 11:58:33 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D2FCE61FD0; Wed, 14 Jan 2026 12:58:32 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="V6Q8hT6f"; 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 8898561FCF for ; Wed, 14 Jan 2026 12:58:31 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id D505E6A8; Wed, 14 Jan 2026 12:58:04 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391884; bh=5TlQ7oJG06sq68busev3Cfh4FsxLdKHCpABeAEu8gMg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=V6Q8hT6fE2Fa0ZZj7C5g4SWmQepQjPN8pLqXNSmWcuwiNxoQtYi6ZQHZdc/qo5LWZ ocEJcEruj4ITMiiaS5Mq9Btx1F8jCEZjMuqdL6Wmkjx3tF0hsUySUhuQsQzTfCeF9e tFDjoncHDHi02H4z6bPt7gMMWQAPxWzXbARyqe+U= From: Stefan Klug Date: Wed, 14 Jan 2026 12:58:04 +0100 Subject: [PATCH v3 11/15] ipa: rkisp1: lsc: Pass sampling positions into samplePolynomial MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-11-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@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 77ed0a95209ac13e82f4ee43f7a22095bb5fd65f..f25bf113bca2b85f8c57abce50f9e564fa570735 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 Wed Jan 14 11:58:05 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25792 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 956C5C3226 for ; Wed, 14 Jan 2026 11:58:35 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4EF9B61FD2; Wed, 14 Jan 2026 12:58:35 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="VD0hiL7q"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8034661FCF for ; Wed, 14 Jan 2026 12:58:34 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id CC2D46A8; Wed, 14 Jan 2026 12:58:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391887; bh=rD3HSOLetuborWWRWDsLC+w6dNo7ZKv+e0gGhq5usA0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=VD0hiL7qNeriECn4wS5W7Ds4hvgDy7yOY8UWTxC9YVkPn2JZX5DaRFeIbReQ8jX8D 8atIjRApYRYFZoTqoLlysMjTsCop3SLO2XmOyuxnr8MFyS7fI6UJyKzeN/7xSYhvln Fo18Iukdhd9aF2Y2TEzh+fDSpKBRCJ656xLFEeZg= From: Stefan Klug Date: Wed, 14 Jan 2026 12:58:05 +0100 Subject: [PATCH v3 12/15] ipa: rkisp1: lsc: Pass crop rectangle as parameter MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-12-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@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 f25bf113bca2b85f8c57abce50f9e564fa570735..5808381fd84dc49fd8548e4d00b2fb4b7015f509 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 Wed Jan 14 11:58:06 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25793 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 70DCDC3226 for ; Wed, 14 Jan 2026 11:58:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 29E8A61FD9; Wed, 14 Jan 2026 12:58:38 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="moEoWxRi"; 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 444D461FD0 for ; Wed, 14 Jan 2026 12:58:37 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 8D4354BB; Wed, 14 Jan 2026 12:58:10 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391890; bh=rfAM+40z3+4FnW7jU8DiB4Ivr2S+775m3xH3XWVKS54=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=moEoWxRiCFnZggP/a1yed0aRoeLvqa9fAIOf89roI5waFS8NT5leSpETMhV4666tT z8LuP7X//E+QgWoIx2JF1QhECcHbC4/9uMpF1l9XgIjl1UJvTQeFP0x2ig1brgaSem NNgjYtpwbIhEH+b+64ED3d7MZQQm2Gft22DF3ibs= From: Stefan Klug Date: Wed, 14 Jan 2026 12:58:06 +0100 Subject: [PATCH v3 13/15] ipa: rkisp1: lsc: Resample polynomial lens shading tables at configure time MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-13-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@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 5808381fd84dc49fd8548e4d00b2fb4b7015f509..8427c48f65b2e6e200f834db506939c6c85fd2a3 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -72,38 +72,127 @@ namespace { constexpr int kColourTemperatureQuantization = 10; -class LscPolynomialLoader +class LscPolynomialShadingDescriptor : public LensShadingCorrection::ShadingDescriptor { public: - LscPolynomialLoader(const Size &sensorSize, - const Rectangle &cropRectangle, - const std::vector &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 Wed Jan 14 11:58:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25794 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 E3F61C3226 for ; Wed, 14 Jan 2026 11:58:41 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9F26661FD2; Wed, 14 Jan 2026 12:58:41 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="BrCoTl1K"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B777A61FD0 for ; Wed, 14 Jan 2026 12:58:40 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 136834BB; Wed, 14 Jan 2026 12:58:14 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391894; bh=l2OgRVSM0AY54TpUR6RuzVrXqx/vDN2aZdAVq0yhDzQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=BrCoTl1KiShlcxnG0cWFPh0v/V36zTz70hnCwQABb8RtusFVL/Pw0F5jzt5If9QBF UDmrQeyHt5fyEHtEec/np2PCDv82DweuNR1SyXLdasjr0eQEdPYEEjlDYXB2UTA3SV +t+g4TU8RriA7Di5ICht2/lp/krdqWSbLCbcAYN8= From: Stefan Klug Date: Wed, 14 Jan 2026 12:58:07 +0100 Subject: [PATCH v3 14/15] libcamera: control_ids: Introduce LensShadingCorrectionEnable MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-14-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@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 Wed Jan 14 11:58:08 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25795 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 6ED1CC3226 for ; Wed, 14 Jan 2026 11:58:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 221B661FD0; Wed, 14 Jan 2026 12:58:45 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="DNHAJzhV"; 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 56E1861FD0 for ; Wed, 14 Jan 2026 12:58:43 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id A2D64177A; Wed, 14 Jan 2026 12:58:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768391896; bh=reCyd+c7EfAMy9j42VXH5hGZUl1gUt8ZhF87wdnRdxE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=DNHAJzhVQxgfNnV6apIkTVKgL8Nd8HCqkpRu719lJ55hNFAcWRChbXDaAY7eDNtgX cwWM9pBHTHkh8Wkc4cgDbccoJhYgha8bIxejCekFXFpT0ILEGO0+4AUPDyyiEqQBJ2 cyy2AZlXgNAq4xYNHHZ6aR54JhxRC8PzaA//tGI4= From: Stefan Klug Date: Wed, 14 Jan 2026 12:58:08 +0100 Subject: [PATCH v3 15/15] ipa: rkisp1: Implement LensShadingCorrectionEnable control MIME-Version: 1.0 Message-Id: <20260114-sklug-lsc-resampling-v2-dev-v3-15-80cd24f4dd61@ideasonboard.com> References: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> In-Reply-To: <20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= 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 v3: - Include LensShadingCorrectionEnable in metadata - Add the queueRequest function in the header in logical order instead of alphabetical order 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 | 67 +++++++++++++++++++++++++++++++++------ src/ipa/rkisp1/algorithms/lsc.h | 7 ++++ src/ipa/rkisp1/ipa_context.h | 13 +++++--- 4 files changed, 74 insertions(+), 15 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 8427c48f65b2e6e200f834db506939c6c85fd2a3..bcf44e83a0b99cc617a1d849d56ca4f288f472a3 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) + << (lsc.enabled ? "Enabling" : "Disabling") << " Lsc"; + + frameContext.lsc.update = true; + } + + frameContext.lsc.enabled = lsc.enabled; +} + /** * \copydoc libcamera::ipa::Algorithm::prepare */ @@ -493,18 +518,28 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context, unsigned int quantizedCt = quantize(ct, kColourTemperatureQuantization); int ctDiff = static_cast(ct) - static_cast(lastAppliedCt_); - /* - * Add a threshold so that oscillations around a quantization step don't - * lead to constant changes. - */ - if (std::abs(ctDiff) < kColourTemperatureQuantization / 2) - return; + /* Check if we can skip the update. */ + if (!frameContext.lsc.update) { + if (!frameContext.lsc.enabled) + return; - if (quantizedCt == lastAppliedQuantizedCt_) - return; + /* + * Add a threshold so that oscillations around a quantization + * step don't lead to constant changes. + */ + if (std::abs(ctDiff) < kColourTemperatureQuantization / 2) + return; + + if (quantizedCt == lastAppliedQuantizedCt_) + 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); @@ -518,6 +553,18 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context, << quantizedCt; } +/** + * \copydoc libcamera::ipa::Algorithm::process + */ +void LensShadingCorrection::process([[maybe_unused]] IPAContext &context, + [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, + [[maybe_unused]] const rkisp1_stat_buffer *stats, + ControlList &metadata) +{ + metadata.set(controls::LensShadingCorrectionEnable, frameContext.lsc.enabled); +} + REGISTER_IPA_ALGORITHM(LensShadingCorrection, "LensShadingCorrection") } /* namespace ipa::rkisp1::algorithms */ diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h index 3097740a6cb2ce9063a4ba087856987a489b0ab6..fb9dcc1a52af4a88a52808346b5da99e3f2b1c87 100644 --- a/src/ipa/rkisp1/algorithms/lsc.h +++ b/src/ipa/rkisp1/algorithms/lsc.h @@ -26,9 +26,16 @@ public: int init(IPAContext &context, const YamlObject &tuningData) override; int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; + void queueRequest(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + const ControlList &controls) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) override; + void process(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + const rkisp1_stat_buffer *stats, + ControlList &metadata) 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 {