From patchwork Tue Jan 20 08:45:43 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25856 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 61349BDCBF for ; Tue, 20 Jan 2026 08:46:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EA6A961FCA; Tue, 20 Jan 2026 09:46:00 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="JrNVdjg3"; 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 E7AF161FB9 for ; Tue, 20 Jan 2026 09:45:57 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 000541733; Tue, 20 Jan 2026 09:45:26 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898727; bh=OcEp1RGR9Yo43utM4YX0sN8zvzSy2va566Bm6G86NKo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=JrNVdjg3gFHqPkQt20cLlviO3BTVdBymd3cTgP/I2UvUFi0oUQB1/lg5XiPX/y7r2 AJVncRIz+pWEmv+8TR8rziUhnOyrGsJU8wUqhaRVFr7Be6OdRmEI+XiNox8leFtnt7 gCuxUmKfnVixMJkbzKX3XkZzKTT/fvLDooq/zM+w= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:43 +0100 Subject: [PATCH v4 01/14] ipa: rkisp1: lsc: Drop unused member variable MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-1-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 Tue Jan 20 08:45:44 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25857 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 7B712BDCBF for ; Tue, 20 Jan 2026 08:46:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 32FBB61FC4; Tue, 20 Jan 2026 09:46:03 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="S2LB0ZJq"; 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 919DA61FC8 for ; Tue, 20 Jan 2026 09:46:00 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 9BC851733; Tue, 20 Jan 2026 09:45:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898729; bh=H02CYr/W/mR0vOF0IrXmTD9xh4WEHezABJY6Jg+EPvo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=S2LB0ZJq7Y730phIx/OX3PBdzviXnDVM3AMPpLqU1KaT9kzLLKtUDfav6bcwYZnVk V1XweDA4G2bVTc5KnBP+ztKkoXGOnJU4R5WdsBc38XzbTFnCKYdaJqp7vPjihHDNuc ePSlzIpHBnM/lhfl0/vSy8XArlNKtcxwa5OJtdHk= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:44 +0100 Subject: [PATCH v4 02/14] ipa: rkisp1: lsc: Drop unused function declaration MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-2-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 Tue Jan 20 08:45:45 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25858 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 0FA48BDCBF for ; Tue, 20 Jan 2026 08:46:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9B78C61FCF; Tue, 20 Jan 2026 09:46:05 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="rTjhraeQ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E2B0361FBF for ; Tue, 20 Jan 2026 09:46:02 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id E5902177D; Tue, 20 Jan 2026 09:45:31 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898732; bh=XclvvXKia3KXTQl/qKvBdoELOBtaOgq+NkY74Ldf5HU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=rTjhraeQrJ84tFGbB3a8o/uh+DPIKsMzH9ZTwSef1cbtzSmkIv5rtgSsp4INW/bAm GhvrJ/lThfrSfIcDgHD+Z/Ij1WsLhvavWhfKla4yVStcpI8KnkPBQWJUJICe6NnLEs ERN97xNP8aT+T33wYrRcG3dUw2mdiVDnh3C5KkC4= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:45 +0100 Subject: [PATCH v4 03/14] ipa: rkisp1: lsc: Replace assert with ASSERT MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-3-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 Tue Jan 20 08:45:46 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25859 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 4F036BDCBF for ; Tue, 20 Jan 2026 08:46:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C19F961FC8; Tue, 20 Jan 2026 09:46:06 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="k7435YHP"; 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 290C561FBC for ; Tue, 20 Jan 2026 09:46:05 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 32FB618D7; Tue, 20 Jan 2026 09:45:34 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898734; bh=OidrM49Hyx9J+ESnrJB6SegC1GcDkuwWcSVuhdfK2Uc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=k7435YHPoi3ZxmHMa50zLCWoVYZ/vPWwZ8e14f7eN3v++PNtUGyWcegeDx7gWtO++ KRgTF5DjSPEnE6bdEOenW2Sx3sapHs5KfYen4In0ayJKFT2t9vuNV4Tt2biyRhq1Ko 7mKNC5syj0C96TLzET3eLe8fmCi32tYER+XpabBY= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:46 +0100 Subject: [PATCH v4 04/14] ipa: rkisp1: lsc: Rename res to positions MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-4-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 Tue Jan 20 08:45:47 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25860 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 04A0FBDCBF for ; Tue, 20 Jan 2026 08:46:12 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 79A4861FD3; Tue, 20 Jan 2026 09:46:11 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="tefhS+U+"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4ADE661FD2 for ; Tue, 20 Jan 2026 09:46:08 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 0EEED18D7; Tue, 20 Jan 2026 09:45:37 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898737; bh=Q66L+qBP3d9HUh5DEB9HQOwvALS5AmnZ9rrQY4rui1k=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=tefhS+U+EelwFYw0Rop/WuNGUcjOQlZSiDrVHfTSlz0ROSl2k4FqaXHlIyxrxIcAR CjRlOjVqtOgi+3AsPO9xFQmNXmJdKc2QIhgrsN1mHcg60m8q4x5PXTnE3BW7QqclMw Xiir8uuNysagLyeR/x9h/iIsfjXgs0tt/x5d29KI= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:47 +0100 Subject: [PATCH v4 05/14] ipa: rkisp1: lsc: Rename res to ret MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-5-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 Tue Jan 20 08:45:48 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25861 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 CCA93BDCBF for ; Tue, 20 Jan 2026 08:46:14 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6147261FD5; Tue, 20 Jan 2026 09:46:14 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="jRpvItzF"; 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 3DD5A61FC0 for ; Tue, 20 Jan 2026 09:46:11 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 4C5371733; Tue, 20 Jan 2026 09:45:40 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898740; bh=jpVW171WvOTT4/C/X32xZQLYDdf8/dod1BqJw5h2R6g=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=jRpvItzFkYmYTrom+OlEThgTDGrKSr50d3RSrIXHYqLU90l5HY3OkinXNYmADU9xA 8JFRoOSPOY/gY4+q3kN2ZYiWYHW0QMHzgfTjiEb8WtlJLghuWkoqE0W8+4jpOqB0+2 EOTz4OfEGsAPJnR9u/2JCRm2qtJ3sIlnoWDmN0DA= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:48 +0100 Subject: [PATCH v4 06/14] ipa: rkisp1: lsc: Rename res to samples MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-6-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 Tue Jan 20 08:45:49 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25862 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 7CE4FBDCBF for ; Tue, 20 Jan 2026 08:46:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4918F61FCE; Tue, 20 Jan 2026 09:46:16 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="gk+qTLj3"; 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 9572A61FC0 for ; Tue, 20 Jan 2026 09:46:13 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 99D251733; Tue, 20 Jan 2026 09:45:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898742; bh=FZ8GonHX/9GBtesyrRJ6bQHXD74/oO2vTKfx8iChULw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=gk+qTLj3jB/MUV62w5MfKdisRW76i26jAe+LXfM4wcxm0YGJlRm0euMS70TohjdV8 fLwruXAAEmEMhp+CY5WlPkbABgGFVjeHN3T85X1Pv8OuDxVCD4TNf9m3nJkYvSmZ8s 0ve9pgx8E+iajb8voXDPoACRchr5qyaNFBWsSXWQ= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:49 +0100 Subject: [PATCH v4 07/14] ipa: rksip1: lsc: Move function definitions out of class MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-7-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 Tue Jan 20 08:45:50 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25863 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 2AE42BDCBF for ; Tue, 20 Jan 2026 08:46:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D6AB761FD8; Tue, 20 Jan 2026 09:46:18 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="U9haRQ4+"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5685161FCF for ; Tue, 20 Jan 2026 09:46:16 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 6438E177D; Tue, 20 Jan 2026 09:45:45 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898745; bh=0l6JnCw672jvY9tLeKTKm0Y+MPFLCOZ2jHu4Q8BNJ4o=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=U9haRQ4+5ERH3IZmW14I2XiaS//MF2YKdSL7VRqgVpkaf5Cka3Ndpo7QpXz0L8cM+ YLmdN3IZ/ZC0a7ReA9EgM8qP4jQV1Vx++tJA3R7vEPs+GJ2r6J4/8ae9mO1qneqPyG /rJnZdZ1+eMGCbBA0CRW3xEGw16kAB5dKmL7XxRA= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:50 +0100 Subject: [PATCH v4 08/14] ipa: rkisp1: lsc: Move local types into anonymous namespace MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-8-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 Tue Jan 20 08:45:51 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25864 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 1F10FBDCBF for ; Tue, 20 Jan 2026 08:46:21 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CCF5761FDA; Tue, 20 Jan 2026 09:46:20 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="UdyVK0F+"; 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 15A6C61FDA for ; Tue, 20 Jan 2026 09:46:19 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 18505177D; Tue, 20 Jan 2026 09:45:48 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898748; bh=eL+k2EL2JfpXoL5X7gV7awPUpsFnyOfOlJ50FdFvmZQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=UdyVK0F+1WuT3wdpzyiNWPrUNnnIgs9FLTGtucTlNhzqvcvLoWJF7e25W5vsNlmS+ VziKtyHFNoFgqwhJ4KWIzRPmtQIsTdhO2s4T2EuRvHI3SGyM5Ay8SjECRaAMMCJmL1 64vIW6cDXh2stgCQB9JoQBHVDu51RJ8WNyb2dRjU= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:51 +0100 Subject: [PATCH v4 09/14] ipa: rkisp1: lsc: Handle quantization locally MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-9-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 c42f74557c7364935254d75ee1fb923d176e0dbd..b7c2ebe43dc0de6716a90b50153cc4dee5d717af 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 Tue Jan 20 08:45:52 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25865 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 D5958BDCBF for ; Tue, 20 Jan 2026 08:46:23 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8E4FD61FD2; Tue, 20 Jan 2026 09:46:23 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cJeOA6F1"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3591E61FCC for ; Tue, 20 Jan 2026 09:46:22 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 3A41B18D7; Tue, 20 Jan 2026 09:45:51 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898751; bh=MOI5N6IRma7MhEbzHhWpvQFpFqWsD3F/bk/CxbcJ024=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=cJeOA6F14UjpubbfI8g4qt2f1hPzEztIBUrXG7wHzLrtlWwAkS6cKbGVhdgNnXhtt J4rCT65eypFDgwakBu0mdVXBP/8SwEtNEY48Q5EwhFQuEj+E4dlFBHw0DYfFJPjn/v u64xVs7mYxfwJq/UdU1NkSUsfuTaPYmtux+bpI2A= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:52 +0100 Subject: [PATCH v4 10/14] ipa: libipa: interpolator: Drop key quantization MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-10-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 Tue Jan 20 08:45:53 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 25866 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 792C2BDCBF for ; Tue, 20 Jan 2026 08:46:26 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 259CF61FDE; Tue, 20 Jan 2026 09:46:26 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="gVZwQy4w"; 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 B18DE61FDC for ; Tue, 20 Jan 2026 09:46:24 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id B747119D3; Tue, 20 Jan 2026 09:45:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898753; bh=WMnOyu5+JCM7fibqidVGqhdcsyz4EZDEPP4/vrCqOhM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=gVZwQy4whLvhQvT9qKyvCKRpRPWzoPfXeTDoQ0ewm+MmoHyGO8EAzQw2QBQIuSrjq mHuohFHF3tDEtKj11xyDvceGEejWfxkUXk2BR//TwW/tlcE3qhRtHyLx5yZpHw6ZEi SPX3s5nv0U6Pbz7yNAeJ+gcoWv0Ivio/T92WexaQ= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:53 +0100 Subject: [PATCH v4 11/14] ipa: rkisp1: lsc: Pass sampling positions into samplePolynomial MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-11-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 b7c2ebe43dc0de6716a90b50153cc4dee5d717af..4420fe72ab99398af6ec37dd03255e650e3e8447 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 Tue Jan 20 08:45: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: 25867 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 2DD76BDCBF for ; Tue, 20 Jan 2026 08:46:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CD30661FE2; Tue, 20 Jan 2026 09:46:28 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="fsjBf4ZG"; 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 F3C3161FCE for ; Tue, 20 Jan 2026 09:46:26 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 067CC1733; Tue, 20 Jan 2026 09:45:55 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898756; bh=XcwPc9jwY/s8ZT9ywCS9TdrSd8iAkWk+6EZyKCNVFE4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=fsjBf4ZGEGdPKNgVu4LiC3y0mLbLbLznP/ZVkOucUVKN8Vj49eYs1JOHqXnh1rOOC 4zYTbzfta9YeAIejuRlkfTQDKDPKFyXilsHtg/SSm45vNy92663hsUAw95zALr/Z2C tUXprohhpJixbcGtIXsp/ceVRCV/mZXltres4LCk= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:54 +0100 Subject: [PATCH v4 12/14] ipa: rkisp1: lsc: Pass crop rectangle as parameter MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-12-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 4420fe72ab99398af6ec37dd03255e650e3e8447..f51c690c2020c8a046fbab8f1da31b9ba4a32ac0 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 Tue Jan 20 08:45: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: 25868 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 03454BDCBF for ; Tue, 20 Jan 2026 08:46:32 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B1F7E61FE7; Tue, 20 Jan 2026 09:46:31 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Vc9ejwwG"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F316461FCF for ; Tue, 20 Jan 2026 09:46:29 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id F18F91733; Tue, 20 Jan 2026 09:45:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898759; bh=Y5/wtOkMWB2jXFFO9zCC9ZAVD1+s/hosRikYh9nqiv8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Vc9ejwwGN2smx/Mnj0f5slB8kTO54/h8TY+f34wKqBcFgVB8YOWdjpdMHi2inbeyU +CwfJgr04L0URnnTHWos1ehwmnHaxupTNYeT2yHorOTdxq/L5hQUKcH0ZQRuAhV3SU vzgz9ZaexFmYISifpmkOAiZY0wzbyFAYVC4PtBGE= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:55 +0100 Subject: [PATCH v4 13/14] ipa: rkisp1: lsc: Resample polynomial lens shading tables at configure time MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-13-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@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 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 f51c690c2020c8a046fbab8f1da31b9ba4a32ac0..8589243ea04f5a712fb2ddd95677a197566f390f 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) 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 Tue Jan 20 08:45: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: 25869 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 D3E49BDCBF for ; Tue, 20 Jan 2026 08:46:34 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 974AF61FDA; Tue, 20 Jan 2026 09:46:34 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="vKhiFVbC"; 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 0032C61FD2 for ; Tue, 20 Jan 2026 09:46:32 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:7f76:a386:d798:7544]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 0976B19D3; Tue, 20 Jan 2026 09:46:02 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768898762; bh=biDI4wv9IbcGO4KRmsyIj6kArY1eDXfDjqfkwKYuMxU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=vKhiFVbCNcHL3Z/tSGBKZGr2fqAkzGbEdylRpNI+aCVQkKhHBOghsjzSd/yb2XQKz A6Lt8d5cfsWNPwc7cA6rwKyYZUk78xaotLmqvVDRdvI/kx5mWknwEOE6TgWpGOLeVk +Kn8p9kG2Ufs2f9vekxZPM02hp1sitil8o+per9M= From: Stefan Klug Date: Tue, 20 Jan 2026 09:45:56 +0100 Subject: [PATCH v4 14/14] ipa: rkisp1: Introduce LensShadingCorrectionEnable control MIME-Version: 1.0 Message-Id: <20260120-sklug-lsc-resampling-v2-dev-v4-14-2411c4be6d6d@ideasonboard.com> References: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> In-Reply-To: <20260120-sklug-lsc-resampling-v2-dev-v4-0-2411c4be6d6d@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , =?utf-8?q?Barnab=C3=A1s_P?= =?utf-8?b?xZFjemU=?= , 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" Add a LensShadingCorrectionEnable control that allows the user to enable or disbale the lens shading correction at runtime. Implement it for the rkisp1. Signed-off-by: Stefan Klug Tested-by: Barnabás Pőcze Reviewed-by: Kieran Bingham --- 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 | 67 +++++++++++++++++++++++++++++++------ src/ipa/rkisp1/algorithms/lsc.h | 7 ++++ src/ipa/rkisp1/ipa_context.h | 13 ++++--- src/libcamera/control_ids_core.yaml | 9 +++++ 5 files changed, 83 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 8589243ea04f5a712fb2ddd95677a197566f390f..8e3878d7e738d4b6212ca09671ed4e66b2dc5102 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 */ @@ -492,18 +517,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 +552,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 { 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. + ...