From patchwork Wed Jan 28 16:00:18 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26012 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 9126BC3200 for ; Wed, 28 Jan 2026 16:00:31 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 482FF61FCB; Wed, 28 Jan 2026 17:00:31 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="vxVbqDT0"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F02EA61FC4 for ; Wed, 28 Jan 2026 17:00:28 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id A8876C6F; Wed, 28 Jan 2026 16:59:51 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769615991; bh=OcEp1RGR9Yo43utM4YX0sN8zvzSy2va566Bm6G86NKo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=vxVbqDT084ScgLBty61OnqLwcOSyYw6EFEjESKkdlooNMGledCeoUYKJ2TfL0eiPf 915LzAzOzULtG88Z/EGz42Pc2aO09yR3XaxkLipKqyPrtZAseHuFtxIVZWjHUNi+dn ps+wV7VwDtrWdvPhZlYrvt7FVKW4+sOGCsnNBMQo= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:18 +0100 Subject: [PATCH v6 01/15] ipa: rkisp1: lsc: Drop unused member variable MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-1-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 28 16:00:19 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26013 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 3B02BC3200 for ; Wed, 28 Jan 2026 16:00:34 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DC0A261FD6; Wed, 28 Jan 2026 17:00:33 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="iWsPC9hD"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 98AEB61FCF for ; Wed, 28 Jan 2026 17:00:31 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 914181E3E; Wed, 28 Jan 2026 16:59:54 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769615994; bh=H02CYr/W/mR0vOF0IrXmTD9xh4WEHezABJY6Jg+EPvo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=iWsPC9hDrhE6TXssXpY7v9NHPlqQjw0+FLnN/cyrEe7SxhK/twHQ4K8M2VUsSPBUj av3ZTqlrcFbuJ8tE0zStidjpFl826mHa38Y0bSD4ITiXwaEPW5roj5CNrjw6Lm+zRE z8zResCuTNx49A3v34ho5XQG6o7WQlb6fFo79LPA= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:19 +0100 Subject: [PATCH v6 02/15] ipa: rkisp1: lsc: Drop unused function declaration MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-2-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 28 16:00:20 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26014 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 38065C3200 for ; Wed, 28 Jan 2026 16:00:36 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E30C261FCB; Wed, 28 Jan 2026 17:00:35 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="OjbNgLae"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 442C061FD8 for ; Wed, 28 Jan 2026 17:00:34 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 3B642C6F; Wed, 28 Jan 2026 16:59:57 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769615997; bh=XclvvXKia3KXTQl/qKvBdoELOBtaOgq+NkY74Ldf5HU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=OjbNgLaeyQWUNyuoSFZvCbA1Q/GlfYlHOYpzAHdeKmR3lBFJxkB0iaDRoU6hOO3kd cuns5Mx9lTSXT5QKPkX8dqtUOdWq9SQpMu2LQK9SWvDHn2iAMsNs42LdqXd2HYi80k gfUD6atnEyqTuSeGCzEwn6Uo5lVCD2Ck9Ienl+0M= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:20 +0100 Subject: [PATCH v6 03/15] ipa: rkisp1: lsc: Replace assert with ASSERT MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-3-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 28 16:00:21 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26015 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 1911EC3200 for ; Wed, 28 Jan 2026 16:00:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C3AC461FD6; Wed, 28 Jan 2026 17:00:38 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="GkNDmIgI"; 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 3F47861FC6 for ; Wed, 28 Jan 2026 17:00:37 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 2E8471F37; Wed, 28 Jan 2026 17:00:00 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616000; bh=hboeKABJ5NBuGXmWn+zavo+DJ3v78x5TaMIKUG30Afw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=GkNDmIgIwSoxsfg34BpdUN7WddpgIWN4sH2afbx2/+XMVsRDs0f6jjv5Lo7bq7b3k ivu28nb4EnM5GnSatr3TzrVLIlLCN+UnpC4Uc11G111GPKPNXONe9nZkh/wxailAPY Vrw+mHuj2JAjKN2lu873qDDMXjXW+I4K5tLC6AKI= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:21 +0100 Subject: [PATCH v6 04/15] ipa: rkisp1: lsc: Rename res to positions MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-4-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , Rui Wang , 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" 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 Reviewed-by: Laurent Pinchart --- Changes in v6: - Improved comment - Collected tag 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..60eb5f5c74ee4a2d38c92dd111bac1c3f71f6420 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 + * top-left quadrant of the grid. This is then mirrored in hardware to + * the other quadrants. 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 28 16:00:22 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26016 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 92D67C3200 for ; Wed, 28 Jan 2026 16:00:41 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5476A61FD3; Wed, 28 Jan 2026 17:00:41 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="gV0+nlOH"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EEFF061FC6 for ; Wed, 28 Jan 2026 17:00:39 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id E096E1E3E; Wed, 28 Jan 2026 17:00:02 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616003; bh=DBu9wTDh9/Ntf4KQXw3Du00JZ63cwVN1Am92HGYH9bA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=gV0+nlOHHz8sAtHn8JWXvw4QAhfsmPBZmbzDNHfb8scUa9WTOR/5TppYBWMWwSKzR 1qZ4pQUJR+pLeNuaehqCAxFv9KO7GsuBiq9VS3tKAY4CyeQJ+F9eWP1cwZhvfnMlcv rU9eMh+1HdsQE7xk3uXFT4N3sC0iG9UsZw7Ba67I= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:22 +0100 Subject: [PATCH v6 05/15] ipa: rkisp1: lsc: Rename res to ret MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-5-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 60eb5f5c74ee4a2d38c92dd111bac1c3f71f6420..972bb57f4a8385b29fa97e7ac3c8025cf1f9980e 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 28 16:00:23 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26017 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 5BD5AC3200 for ; Wed, 28 Jan 2026 16:00:44 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CB15061FDF; Wed, 28 Jan 2026 17:00:43 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="VJrUIpBG"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7AFC561FDC for ; Wed, 28 Jan 2026 17:00:42 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 65330201D; Wed, 28 Jan 2026 17:00:05 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616005; bh=bUAx3KWol+8DHvGGtMRVj9JEIzD3b8KDiHv8Y1padcU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=VJrUIpBGYavDPezW6hhiLrQNdUyUCQ4GeUX3VVZ+MRIrW0o1CUY7OecDHg6mMVut+ TPD2d34aDSy7MNiErZjdMmvu39w6CXLhKx5O74PdrjUWRGwRrC7KfG2IwdDfQ7Adad M81i8HpIKuEiYlBEf0aFb1Zzz9i90YvwmAShhzT8= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:23 +0100 Subject: [PATCH v6 06/15] ipa: rkisp1: lsc: Rename res to samples MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-6-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 972bb57f4a8385b29fa97e7ac3c8025cf1f9980e..4b7aaaf05abd7e56231bb231d36ad07778f93540 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 28 16:00:24 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26018 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 F4106C3200 for ; Wed, 28 Jan 2026 16:00:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BE0A261FD3; Wed, 28 Jan 2026 17:00:46 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="maoSs2eo"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BE8F861FD0 for ; Wed, 28 Jan 2026 17:00:44 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id AEF7C201D; Wed, 28 Jan 2026 17:00:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616007; bh=M3RgGvg8z1f9pxF5kghInt+Ccypok8mkF6tm/HFHNY8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=maoSs2eoGq7Ekl8jCZjo075wWN5Mbn1mzJjSlkRsZ6nrf0A0HFVnvZolffEo2tK99 NqzDwsPtFqrDffwM2CZR8ormU8K02+kZhAkSTbKBQKTQ/tKWe9nybRNf+Xr+ToYZFt oz8GtHlDRblocShM+UdekUW5AGgomsQU/FBHpE5Y= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:24 +0100 Subject: [PATCH v6 07/15] ipa: rksip1: lsc: Move function definitions out of class MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-7-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 v6: - Fixed rebase conflict due to earlier update in v6 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 4b7aaaf05abd7e56231bb231d36ad07778f93540..a5c15ea3b293c64f458dc9d4b4b06232db8673cc 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 - * top-left quadrant of the grid. This is then mirrored in hardware to - * the other quadrants. 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 top-left + * quadrant of the grid. This is then mirrored in hardware to the other + * quadrants. 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 28 16:00:25 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26019 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 8E3E3C3200 for ; Wed, 28 Jan 2026 16:00:49 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4D09861FDF; Wed, 28 Jan 2026 17:00:49 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="IsKu/4Mv"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9992261FDB for ; Wed, 28 Jan 2026 17:00:47 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 8B5BC1FBC; Wed, 28 Jan 2026 17:00:10 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616010; bh=KNKOEEbYPoPX975ACEBQGf9aQl/6x8eHXZAj1uY313s=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=IsKu/4Mv+j6/lNt+GFBTTmnykF4sQWjDiY4TXxOZTP/+Dr2l43rOdcydCPIS+jKPj w46s/hRkhwRit/GJU2Ee02uS807Mvhmgrbj9M4jC0CvCV872xH0OZNJGpnfxnQ6CYi lhRRIRAhHDfnNX2AaI9LJrHXOYaihk312oFvaK/A= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:25 +0100 Subject: [PATCH v6 08/15] ipa: rkisp1: lsc: Move local types into anonymous namespace MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-8-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 a5c15ea3b293c64f458dc9d4b4b06232db8673cc..99e1e05f1d8b8157c2bbb8ee2f94cedb152009ca 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 28 16:00:26 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26020 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 20D9BC3200 for ; Wed, 28 Jan 2026 16:00:53 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C7C9061FEE; Wed, 28 Jan 2026 17:00:52 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cV12atsf"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D22B461FD3 for ; Wed, 28 Jan 2026 17:00:50 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id CD2A02813; Wed, 28 Jan 2026 17:00:13 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616013; bh=IDs+b0zQ8yuVkCkQntDCcy1ZyW1qjFmEW5gRQy3Fhu4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=cV12atsfzKs51Zlv0IVTZ3S05EWGaXLNd6BsIQJClKmX0/ej53gOhfBqaX+9Npqhn dZIssr/8kAUGaPaFQeBElzkdXA/dSwZ2ceRoQ44BmLNFQMLINHuK1TCYzqp+XH4fi/ mCTFYXe/jbpABv/8SaYSsVzUmjMsuMI6wX3RABLs= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:26 +0100 Subject: [PATCH v6 09/15] ipa: rkisp1: lsc: Handle quantization locally MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-9-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 functionality in the Interpolator type 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 v4: - Small fix in commit message - Replaced manual std::abs(signed diff) by utils::abs_diff() - Collected tag 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 | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 99e1e05f1d8b8157c2bbb8ee2f94cedb152009ca..daf5c9a9b8fddf290a55471c4dce608f1b8ec82a 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,23 @@ 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); + + /* + * Add a threshold so that oscillations around a quantization step don't + * lead to constant changes. + */ + if (utils::abs_diff(ct, lastAppliedCt_) < 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 28 16:00:27 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26021 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 F3C05C3200 for ; Wed, 28 Jan 2026 16:00:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AC37F61FF3; Wed, 28 Jan 2026 17:00:55 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="DZFwc95D"; 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 E8C6561FD3 for ; Wed, 28 Jan 2026 17:00:53 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id D817D27F9; Wed, 28 Jan 2026 17:00:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616017; bh=MOI5N6IRma7MhEbzHhWpvQFpFqWsD3F/bk/CxbcJ024=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=DZFwc95D1Ke3f+NCpWVIm47TK87ayynhTpuoaYGUvcjPqKEA8dFfPfcOEJTxPutPH bINZ2XzrQMXnCgvGjlU1o/KQ0erwbokuTQQOMx2K1WS3samF4/GYZCDgMdpwFvs2Qt VKI5nIXDKN4NBMDGu4lPA1EDi1hwnOlzBoPU8yEg= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:27 +0100 Subject: [PATCH v6 10/15] ipa: libipa: interpolator: Drop key quantization MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-10-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 28 16:00:28 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26022 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 DA48DC3200 for ; Wed, 28 Jan 2026 16:00:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 782CB61FDE; Wed, 28 Jan 2026 17:00:57 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="u1pfIGDg"; 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 AE75961FD3 for ; Wed, 28 Jan 2026 17:00:56 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 9F4F32815; Wed, 28 Jan 2026 17:00:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616019; bh=HFW64clCVsFVVMzqyef9BqiKV0Efp7Dv7GudBjgZ3b0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=u1pfIGDgVnM2I4SfojXMUxJ4+rLubm0qrQHnfHjRSuSMk9HdL1bMbaZoTNes8dp5v pWEoPbYWd74xeKuGH9wTx2HlXDbG4Ik1WjvvjiZ3y5rraCCfthfJDQTwkOwXzR5XG/ i1QzNKV8BgTz8anD4hJR+0ymhPsqpwuGO9OpoQrw= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:28 +0100 Subject: [PATCH v6 11/15] ipa: rkisp1: lsc: Pass sampling positions into samplePolynomial MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-11-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 daf5c9a9b8fddf290a55471c4dce608f1b8ec82a..a70551ab70afec684d9c92bb9769c63d0f4f2653 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 28 16:00:29 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26023 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 DAB5CC3200 for ; Wed, 28 Jan 2026 16:01:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9E37961FDF; Wed, 28 Jan 2026 17:01:00 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="YSgpn1nk"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7FD9261FD3 for ; Wed, 28 Jan 2026 17:00:59 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 751F32813; Wed, 28 Jan 2026 17:00:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616022; bh=0govxU6i4RBOa7z8mlKhV0SQ10iD8SEaaf40LkS5F2c=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=YSgpn1nkt3pryqNvTt04huE+XXuDzJiAeOrbD39A5vREFs91Wu+P9Cnq/XZZ3xZmf p1OtLNLLqTWXuWIZOkbmZKzqqiDnyi86iSrBVlyERXWY1Hv6epPwxLsuKLwvk1Lnrz X+KNA2Jdm96/dzecRY6Bg21tUwQYsyJCMrXY4sS8= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:29 +0100 Subject: [PATCH v6 12/15] ipa: rkisp1: lsc: Pass crop rectangle as parameter MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-12-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 a70551ab70afec684d9c92bb9769c63d0f4f2653..761e5a76bc88bc8cceacf2922846c7b50808aa63 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 28 16:00:30 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26024 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 B4C35C3200 for ; Wed, 28 Jan 2026 16:01:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 762D261FDE; Wed, 28 Jan 2026 17:01:03 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="UypUIAic"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B6A9E61FD3 for ; Wed, 28 Jan 2026 17:01:02 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id A5A4A201D; Wed, 28 Jan 2026 17:00:25 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616025; bh=Y77ULtESPBeSbNon3B+gXWWQSKTPCvQSrqTBDDToHvQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=UypUIAicmo1q8NHWX4x/EXpz3HJvu7yFJFZYbJV6PGHHGIze8rWPKLP4zjqnZal89 0rLyN0+uFinAGo9ZuCSNTul8JE7GUs9RVc7aJkVUsxZjKk8+zrAonr+5/DFKGwkE05 ekgTVdQilO60dqDZG4FDv1ht8Jl+tdgpTktilX1w= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:30 +0100 Subject: [PATCH v6 13/15] ipa: rkisp1: lsc: Resample polynomial lens shading tables at configure time MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-13-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@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 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 Reviewed-by: Kieran Bingham Reviewed-by: Barnabás Pőcze --- Changes in v6: - Fixed rebase conflicts due to earlier changes in v6 Changes in v4: - Removed trailing dot from commit message - Added missing 'override' - Collected tags 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 761e5a76bc88bc8cceacf2922846c7b50808aa63..c7a40a64bc94b6a5b846e266261e0c102f4010f5 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 top-left + * quadrant of the grid. This is then mirrored in hardware to the other + * quadrants. 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 top-left - * quadrant of the grid. This is then mirrored in hardware to the other - * quadrants. 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) override + { + 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 28 16:00:31 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26025 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 034BAC3200 for ; Wed, 28 Jan 2026 16:01:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B94AE61FDE; Wed, 28 Jan 2026 17:01:06 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="SnZvPjLj"; 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 A9F9361FD3 for ; Wed, 28 Jan 2026 17:01:05 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id A735D27F9; Wed, 28 Jan 2026 17:00:28 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616028; bh=39NlPgCqW5Nob5gyChWODILLQLQ7MiOEgExqaUFdo7A=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=SnZvPjLjkdYUWNzSWNAcCj+J31YYfOMV4GO5Fg+iY0v/cNGaTZFISatJruuyzD9D3 FokFkX//76bmbqH3XmYrkVTZEaHul71pcBpKFsgTFxUTS5ezN11RQfxPfpli3ftKW4 gHUHU7JO9Gt9baJFkaovOgTxx5hSBG8F4YQ4Nx1Y= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:31 +0100 Subject: [PATCH v6 14/15] libcamera: control_ids: Introduce LensShadingCorrectionEnable MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-14-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , Jacopo Mondi , Kieran Bingham , 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" Introduce a LensShadingCorrectionEnable control to enable and disable LSC. This is useful to assess the working and quality of the lens shading correction at runtime. While at it drop the reference to the tuning file in the description of the LensDewarpEnable control, as that information doesn't belong to the controls. Signed-off-by: Jacopo Mondi Signed-off-by: Stefan Klug Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- Changes in v6: - Improved the control description - Dropped the reference to the tuning file - Collected tags Changes in v5: - Readd this patch to have a separate patch for the control id - Dropped android specific changes 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/libcamera/control_ids_core.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml index 8e99bd84825f6060dbc323be3f4b0cd6283e0942..f26a1b1b08bd1684cb76d75ecc32bdb9f8b0f6e5 100644 --- a/src/libcamera/control_ids_core.yaml +++ b/src/libcamera/control_ids_core.yaml @@ -1353,7 +1353,12 @@ controls: type: bool direction: inout description: | - Enable or disable lens dewarping. This control is only available if lens - dewarp parameters are configured in the tuning file. + Enable or disable lens dewarping. + + - LensShadingCorrectionEnable: + type: bool + direction: inout + description: | + Enable or disable the lens shading correction. ... From patchwork Wed Jan 28 16:00:32 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26026 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 912D2C3200 for ; Wed, 28 Jan 2026 16:01:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 49B4562000; Wed, 28 Jan 2026 17:01:10 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="qrqOGK44"; 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 E44C961FDB for ; Wed, 28 Jan 2026 17:01:08 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:1a60:e70f:ec38:13a9]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id B0B921FBC; Wed, 28 Jan 2026 17:00:31 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769616031; bh=7Wx67UStwgEoLnP7Xbl/rkT50e8YqwzzTWg/UOnk1YA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=qrqOGK44AakP0NTFF5wmh/ES3xpjh7jw4jx1MkPyGpV+a/GruIIM7kHAf3cwjBi8O ++BJq6qUdmAc7zRAVgiJAwXR3S36e8FpelKf1vZqCS4aXL73rTm2TD3IV5yIUwVIP1 kADkMUESw/TsAm9GRCNSugQ9ty0Zgiarz3DpYoFs= From: Stefan Klug Date: Wed, 28 Jan 2026 17:00:32 +0100 Subject: [PATCH v6 15/15] ipa: rkisp1: Implement LensShadingCorrectionEnable control MIME-Version: 1.0 Message-Id: <20260128-sklug-lsc-resampling-v2-dev-v6-15-af7d95f03d22@ideasonboard.com> References: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> In-Reply-To: <20260128-sklug-lsc-resampling-v2-dev-v6-0-af7d95f03d22@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , Kieran Bingham , 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" Implement the LensShadingCorrectionEnable control for rkisp1. Signed-off-by: Stefan Klug Tested-by: Barnabás Pőcze Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- Changes in v6: - Wrapped a long line - Collected tag Changes in v5: - Split patch 14 into two again, to have a separate patch for control_ids_core.yaml Changes in v4: - Squahed patch 14 (addition od the LSC control) and 15 (implementation) into one. - Collected tag 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 | 68 +++++++++++++++++++++++++++++++++------ src/ipa/rkisp1/algorithms/lsc.h | 7 ++++ src/ipa/rkisp1/ipa_context.h | 13 +++++--- 4 files changed, 75 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 c7a40a64bc94b6a5b846e266261e0c102f4010f5..c6982e6b4b10a321744e0101cdc0e07e23fb0185 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -416,6 +416,9 @@ 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 +463,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 +484,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 */ @@ -492,18 +518,28 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context, uint32_t ct = frameContext.awb.temperatureK; unsigned int quantizedCt = quantize(ct, kColourTemperatureQuantization); - /* - * Add a threshold so that oscillations around a quantization step don't - * lead to constant changes. - */ - if (utils::abs_diff(ct, lastAppliedCt_) < 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 (utils::abs_diff(ct, lastAppliedCt_) < 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); @@ -517,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 {