From patchwork Mon Apr 20 18:39:39 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26522 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 C86ACBDCBD for ; Mon, 20 Apr 2026 18:40:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6318762EE7; Mon, 20 Apr 2026 20:40:08 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="WpQRQb2j"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 66D7862EC0 for ; Mon, 20 Apr 2026 20:40:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1776710405; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GQ4tlzw/XZCxbfakwxkGebHivcMGTk5iZAwLF1kv+XU=; b=WpQRQb2jFsl4MSKiEkCr8Q1BFbPf5RtZVbEDnbawJJXIRWu+fDPrD0PqMcd9hc4318y4kn EjfYPrWcxqo2832kS55VUL07EO1rBXYLV+ewAWG0Gul6fyIGwNsjxfHu+y6JusXZyRcVTY DbbEgso6X9LQbM31eaCPr+EfTEEU9R4= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-271-3WdLyOHRP_G5vvivW0RpWg-1; Mon, 20 Apr 2026 14:40:01 -0400 X-MC-Unique: 3WdLyOHRP_G5vvivW0RpWg-1 X-Mimecast-MFC-AGG-ID: 3WdLyOHRP_G5vvivW0RpWg_1776710400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7F1D91800352; Mon, 20 Apr 2026 18:39:59 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.48.16]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id F1071180047F; Mon, 20 Apr 2026 18:39:56 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Hans de Goede , Bryan O'Donoghue , Rick ten Wolde , Milan Zamazal Subject: [RFC PATCH v2 1/8] libcamera: software_isp: egl: Add gl_scale_param to createTexture2D() Date: Mon, 20 Apr 2026 20:39:39 +0200 Message-ID: <20260420183949.110548-2-mzamazal@redhat.com> In-Reply-To: <20260420183949.110548-1-mzamazal@redhat.com> References: <20260420183949.110548-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Cs1AqdhlLgsf8xcO0s_tpyR6kVNvfmrNlOu9zC5ZtQI_1776710400 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" From: Xander Pronk Add a gl_scale_param to createTexture2D() to allow overriding the currently hardcoded GL_NEAREST value. This is needed for grid-based lens shading interpolation, which is implemented in followup patches. Reviewed-by: Bryan O'Donoghue Co-developed-by: Rick ten Wolde Signed-off-by: Rick ten Wolde Signed-off-by: Xander Pronk Signed-off-by: Milan Zamazal --- include/libcamera/internal/egl.h | 3 ++- src/libcamera/egl.cpp | 8 +++++--- src/libcamera/software_isp/debayer_egl.cpp | 4 +++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h index 8a2d96d7a..37cd8dc83 100644 --- a/include/libcamera/internal/egl.h +++ b/include/libcamera/internal/egl.h @@ -105,7 +105,8 @@ public: int createInputDMABufTexture2D(eGLImage &eglImage, int fd); int createOutputDMABufTexture2D(eGLImage &eglImage, int fd); void destroyDMABufTexture(eGLImage &eglImage); - void createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, void *data); + void createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, + const void *data, GLint glFilterParam); void pushEnv(std::vector &shaderEnv, const char *str); void makeCurrent(); diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp index 5b9bbf410..6ba6888c4 100644 --- a/src/libcamera/egl.cpp +++ b/src/libcamera/egl.cpp @@ -229,13 +229,15 @@ void eGL::destroyDMABufTexture(eGLImage &eglImage) * \param[in] width Texture width in pixels * \param[in] height Texture height in pixels * \param[in] data Pointer to pixel data, or nullptr for uninitialised texture + * \param[in] glFilterParam GL texture filter setting * * Creates a 2D texture from a CPU-accessible memory buffer. The texture * is configured with nearest filtering and clamp-to-edge wrapping. This * is useful for uploading static data like lookup tables or uniform color * matrices to the GPU. */ -void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, void *data) +void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, + const void *data, GLint glFilterParam) { ASSERT(tid_ == Thread::currentId()); @@ -246,8 +248,8 @@ void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); // Nearest filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glFilterParam); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glFilterParam); // Wrap to edge to avoid edge artifacts glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 2ad258bca..08e513eaf 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -502,7 +502,9 @@ int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParam egl_.makeCurrent(); /* Create a standard texture input */ - egl_.createTexture2D(*eglImageBayerIn_, glFormat_, inputConfig_.stride / bytesPerPixel_, height_, in.planes()[0].data()); + egl_.createTexture2D(*eglImageBayerIn_, glFormat_, + inputConfig_.stride / bytesPerPixel_, height_, + in.planes()[0].data(), GL_NEAREST); /* Generate the output render framebuffer as render to texture */ egl_.createOutputDMABufTexture2D(*eglImageBayerOut_, out_fd); From patchwork Mon Apr 20 18:39:40 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26523 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 73A14BDCBD for ; Mon, 20 Apr 2026 18:40:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3AAD862EE2; Mon, 20 Apr 2026 20:40:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="AeJGSyI1"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8CD3662ED7 for ; Mon, 20 Apr 2026 20:40:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1776710406; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wyg3vFIG4dJxLaBsUjHBlBfxdNCFBHSGXi+Ae4I9/UI=; b=AeJGSyI1lI8yawhCbT45SyezeFbUnwnRAxDCXqBJU8J3CECaPVEV7cy3Zev+70iq6uV7jY AdX+uRb9BlEw/GB0FAqIBjibxeBlGxxzVQwD0M4ki7HUMbw0LpoPqIBeOUoX90ZQWuWDkG kJ8jRG5hr6a7w7rcdRQ39ufQRDSHe74= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-687-o7AMKVsEM3ieEPr_bvSkuA-1; Mon, 20 Apr 2026 14:40:03 -0400 X-MC-Unique: o7AMKVsEM3ieEPr_bvSkuA-1 X-Mimecast-MFC-AGG-ID: o7AMKVsEM3ieEPr_bvSkuA_1776710402 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 471D81956088; Mon, 20 Apr 2026 18:40:02 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.48.16]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1D6E8180047F; Mon, 20 Apr 2026 18:39:59 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Hans de Goede , Rick ten Wolde , Milan Zamazal Subject: [RFC PATCH v2 2/8] libcamera: software_isp: Add LSC data to DebayerParams Date: Mon, 20 Apr 2026 20:39:40 +0200 Message-ID: <20260420183949.110548-3-mzamazal@redhat.com> In-Reply-To: <20260420183949.110548-1-mzamazal@redhat.com> References: <20260420183949.110548-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: zjW7VX9jWfzSJ89lE7KYXYo2KQluHYfLuRTVKvSImnE_1776710402 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" From: Xander Pronk Add a lookup table for grid-based lens shading correction to debayer params. The lookup table is in the format of an RGB texture to be passed to debayering. The parameter is filled in by LSC algorithm implemented in a followup patch. If the algorithm is not enabled, the parameter content is arbitrary and the parameter may not be used. The parameter is currently unused, its handling is implemented in a followup patch. There is no special meaning about the selected grid size, it's just one of the smaller common sizes. Co-developed-by: Rick ten Wolde Signed-off-by: Rick ten Wolde Signed-off-by: Xander Pronk Signed-off-by: Milan Zamazal --- .../internal/software_isp/debayer_params.h | 5 +++++ src/libcamera/software_isp/debayer.cpp | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h index 6772b43bc..3f25d3219 100644 --- a/include/libcamera/internal/software_isp/debayer_params.h +++ b/include/libcamera/internal/software_isp/debayer_params.h @@ -10,6 +10,7 @@ #pragma once +#include #include #include "libcamera/internal/matrix.h" @@ -25,6 +26,10 @@ struct DebayerParams { float gamma = 1.0; float contrastExp = 1.0; RGB gains = RGB({ 1.0, 1.0, 1.0 }); + + static constexpr unsigned int kLscGridSize = 16; + using LscLookupTable = std::array; + LscLookupTable lscLut{}; }; } /* namespace libcamera */ diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index a6bceb58b..b60ebcd9b 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -49,6 +49,24 @@ namespace libcamera { * \brief Contrast value to be used as an exponent */ +/** + * \var DebayerParams::kLscGridSize + * \brief Number of lens shading grid areas in one direction + */ + +/** + * \typedef DebayerParams::LscLookupTable + * \brief Lookup table for lens shading correction + * + * It's an array of bytes to be later used as a texture. + * The bytes are in row - column - RGB order. + */ + +/** + * \var DebayerParams::lscLut + * \brief Lens shading lookup table + */ + /** * \class Debayer * \brief Base debayering class From patchwork Mon Apr 20 18:39:41 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26524 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 7C642BDCBD for ; Mon, 20 Apr 2026 18:40:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 169A962EEC; Mon, 20 Apr 2026 20:40:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="V2Q2pL6z"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BF76C62EDE for ; Mon, 20 Apr 2026 20:40:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1776710406; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nT+0moHosv4tRpd4gfW9X5s1r+t8wPBaJAM2u1YjK04=; b=V2Q2pL6ztmXEeGsoXISwafWV4R0/+hQ3okhRuyO4AnAp1nm7sVcqRj6PkaHWV4o6ErRZvH APmR90Ll58ZAm6qLuhD8X0KZEJl2TyaiLzwUTu6dHmh8lvUYjFI4g2bb6RG09I/8eCGfAl ybuW69EaaUgDrW6hQhyxM/btaYa8zWA= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-611-mYJNx_tHNUK7BsNQJkdImA-1; Mon, 20 Apr 2026 14:40:05 -0400 X-MC-Unique: mYJNx_tHNUK7BsNQJkdImA-1 X-Mimecast-MFC-AGG-ID: mYJNx_tHNUK7BsNQJkdImA_1776710404 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B673319560A7; Mon, 20 Apr 2026 18:40:04 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.48.16]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E282F180047F; Mon, 20 Apr 2026 18:40:02 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Hans de Goede Subject: [RFC PATCH v2 3/8] ipa: simple: Introduce default temperature value Date: Mon, 20 Apr 2026 20:39:41 +0200 Message-ID: <20260420183949.110548-4-mzamazal@redhat.com> In-Reply-To: <20260420183949.110548-1-mzamazal@redhat.com> References: <20260420183949.110548-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: k6fgkyyGXVJHst5wCaUYnUgxqFUB-WwC3Kn8lQgbRtI_1776710404 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" Some algorithms use interpolated values based on temperature. Temperature is computed in the AWB algorithm. Technically, the AWB algorithm can be disabled and then no temperature is computed. Let's avoid implicit assumptions and introduce a constant for a default temperature value and make the temperature value optional. This is currently used by the CCM algorithm. It will be used also by the LSC algorithm in the followup patch. The default temperature value of 6500 is just a common value, there is no special reason to use this or another value. Signed-off-by: Milan Zamazal --- src/ipa/simple/algorithms/awb.cpp | 4 ++-- src/ipa/simple/algorithms/awb.h | 4 +++- src/ipa/simple/algorithms/ccm.cpp | 5 ++++- src/ipa/simple/ipa_context.h | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp index f5c88ea6f..961126c0d 100644 --- a/src/ipa/simple/algorithms/awb.cpp +++ b/src/ipa/simple/algorithms/awb.cpp @@ -96,11 +96,11 @@ void Awb::process(IPAContext &context, RGB rgbGains{ { 1 / gains.r(), 1 / gains.g(), 1 / gains.b() } }; context.activeState.awb.temperatureK = estimateCCT(rgbGains); - metadata.set(controls::ColourTemperature, context.activeState.awb.temperatureK); + metadata.set(controls::ColourTemperature, context.activeState.awb.temperatureK.value_or(0)); LOG(IPASoftAwb, Debug) << "gain R/B: " << gains << "; temperature: " - << context.activeState.awb.temperatureK; + << context.activeState.awb.temperatureK.value_or(0); } REGISTER_IPA_ALGORITHM(Awb, "Awb") diff --git a/src/ipa/simple/algorithms/awb.h b/src/ipa/simple/algorithms/awb.h index ad993f39c..df46baee4 100644 --- a/src/ipa/simple/algorithms/awb.h +++ b/src/ipa/simple/algorithms/awb.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ /* - * Copyright (C) 2024-2025 Red Hat Inc. + * Copyright (C) 2024-2026 Red Hat Inc. * * Auto white balance */ @@ -13,6 +13,8 @@ namespace libcamera { namespace ipa::soft::algorithms { +constexpr unsigned int kDefaultTemperature = 6500; + class Awb : public Algorithm { public: diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp index 911a5af2c..6bac45006 100644 --- a/src/ipa/simple/algorithms/ccm.cpp +++ b/src/ipa/simple/algorithms/ccm.cpp @@ -15,6 +15,8 @@ #include "libcamera/internal/matrix.h" +#include "awb.h" + namespace { constexpr unsigned int kTemperatureThreshold = 100; @@ -44,7 +46,8 @@ int Ccm::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData void Ccm::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, IPAFrameContext &frameContext, [[maybe_unused]] DebayerParams *params) { - const unsigned int ct = context.activeState.awb.temperatureK; + const unsigned int ct = + context.activeState.awb.temperatureK.value_or(kDefaultTemperature); /* Change CCM only on bigger temperature changes. */ if (!currentCcm_ || diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h index 34f7403a4..c4bd91bb0 100644 --- a/src/ipa/simple/ipa_context.h +++ b/src/ipa/simple/ipa_context.h @@ -50,7 +50,7 @@ struct IPAActiveState { struct { RGB gains; - unsigned int temperatureK; + std::optional temperatureK; } awb; Matrix combinedMatrix; From patchwork Mon Apr 20 18:39:42 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26525 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 3CC62BDCBD for ; Mon, 20 Apr 2026 18:40:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EDBA662EE8; Mon, 20 Apr 2026 20:40:15 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="GY2Fe+VG"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 67DE462EE1 for ; Mon, 20 Apr 2026 20:40:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1776710413; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Bnw9nfH1ZhpnFRoEbZjS/FiSg/RZ0hfGasNhk6TuCFQ=; b=GY2Fe+VGzwYd3JervV43w3rVnoXgU/TbXutTYHDyT/o0JR1DozbZAU+llQLycvSdlcadUT lOAyU23ZjIA06v1gaeA0RmDv8GOvwJwpluJcK0HQmZDSbMTq0+ELkTp1/U50LeTRcfQXFc T3T8LwuMlKwrIljPn8K9IDjd/CKm6fc= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-353-ahUBH6KmOFO_7Y3qpId2MQ-1; Mon, 20 Apr 2026 14:40:08 -0400 X-MC-Unique: ahUBH6KmOFO_7Y3qpId2MQ-1 X-Mimecast-MFC-AGG-ID: ahUBH6KmOFO_7Y3qpId2MQ_1776710407 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C7757180034D; Mon, 20 Apr 2026 18:40:07 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.48.16]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 76BAD180047F; Mon, 20 Apr 2026 18:40:05 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Hans de Goede , Rick ten Wolde , Milan Zamazal Subject: [RFC PATCH v2 4/8] ipa: simple: Add LSC algorithm Date: Mon, 20 Apr 2026 20:39:42 +0200 Message-ID: <20260420183949.110548-5-mzamazal@redhat.com> In-Reply-To: <20260420183949.110548-1-mzamazal@redhat.com> References: <20260420183949.110548-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: xdR2TpDEx15_2UJWYB4ssRSGLqqkZa8UBqWXje-J9ps_1776710407 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" From: Xander Pronk The lens shading algorithm uses grid-based interpolation. The grid values are specified in a tuning file. The interpolated grid is transformed to an array to be used as an RGB texture in debayering. Co-developed-by: Rick ten Wolde Signed-off-by: Rick ten Wolde Signed-off-by: Xander Pronk Signed-off-by: Milan Zamazal --- src/ipa/simple/algorithms/lsc.cpp | 63 +++++++++++++++++++++++++++ src/ipa/simple/algorithms/lsc.h | 41 +++++++++++++++++ src/ipa/simple/algorithms/meson.build | 1 + 3 files changed, 105 insertions(+) create mode 100644 src/ipa/simple/algorithms/lsc.cpp create mode 100644 src/ipa/simple/algorithms/lsc.h diff --git a/src/ipa/simple/algorithms/lsc.cpp b/src/ipa/simple/algorithms/lsc.cpp new file mode 100644 index 000000000..9588dc95d --- /dev/null +++ b/src/ipa/simple/algorithms/lsc.cpp @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Lens shading correction + */ + +#include "lsc.h" + +#include + +#include "awb.h" + +namespace libcamera { + +namespace ipa::soft::algorithms { + +LOG_DEFINE_CATEGORY(IPASoftLsc) + +int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) +{ + int ret_r = lscR.readYaml(tuningData["grids"], "ct", "r"); + int ret_g = lscG.readYaml(tuningData["grids"], "ct", "g"); + int ret_b = lscB.readYaml(tuningData["grids"], "ct", "b"); + + if (ret_r < 0 || ret_g < 0 || ret_b < 0) { + LOG(IPASoftLsc, Error) + << "Failed to parse 'lsc' parameter from tuning file."; + return -EINVAL; + } + + return 0; +} + +int Lsc::configure([[maybe_unused]] IPAContext &context, + [[maybe_unused]] const IPAConfigInfo &configInfo) +{ + return 0; +} + +void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, + [[maybe_unused]] IPAFrameContext &frameContext, DebayerParams *params) +{ + unsigned int ct = + context.activeState.awb.temperatureK.value_or(kDefaultTemperature); + + const LscMatrix matrixR = lscR.getInterpolated(ct); + const LscMatrix matrixG = lscG.getInterpolated(ct); + const LscMatrix matrixB = lscB.getInterpolated(ct); + + DebayerParams::LscLookupTable lut; + constexpr unsigned int gridSize = DebayerParams::kLscGridSize; + for (unsigned int i = 0, j = 0; i < gridSize * gridSize; i++) { + lut[j++] = matrixR.data()[i]; + lut[j++] = matrixG.data()[i]; + lut[j++] = matrixB.data()[i]; + } + params->lscLut = lut; +} + +REGISTER_IPA_ALGORITHM(Lsc, "Lsc") + +} /* namespace ipa::soft::algorithms */ + +} /* namespace libcamera */ diff --git a/src/ipa/simple/algorithms/lsc.h b/src/ipa/simple/algorithms/lsc.h new file mode 100644 index 000000000..9afdac0de --- /dev/null +++ b/src/ipa/simple/algorithms/lsc.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Lens shading correction + */ + +#pragma once + +#include "libcamera/internal/matrix.h" + +#include + +#include "algorithm.h" + +namespace libcamera { + +namespace ipa::soft::algorithms { + +class Lsc : public Algorithm +{ +public: + Lsc() = default; + ~Lsc() = default; + + int init(IPAContext &context, const YamlObject &tuningData) override; + int configure(IPAContext &context, + const IPAConfigInfo &configInfo) override; + void prepare(IPAContext &context, + const uint32_t frame, + IPAFrameContext &frameContext, + DebayerParams *params) override; + +private: + using LscMatrix = Matrix; + Interpolator lscR; + Interpolator lscG; + Interpolator lscB; +}; + +} /* namespace ipa::soft::algorithms */ + +} /* namespace libcamera */ diff --git a/src/ipa/simple/algorithms/meson.build b/src/ipa/simple/algorithms/meson.build index 73c637220..c9f6e5590 100644 --- a/src/ipa/simple/algorithms/meson.build +++ b/src/ipa/simple/algorithms/meson.build @@ -6,4 +6,5 @@ soft_simple_ipa_algorithms = files([ 'agc.cpp', 'blc.cpp', 'ccm.cpp', + 'lsc.cpp', ]) From patchwork Mon Apr 20 18:39:43 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26527 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 74E4FC32F6 for ; Mon, 20 Apr 2026 18:40:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 132FC62EEC; Mon, 20 Apr 2026 20:40:19 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="FU4P/QHl"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 050B862EE9 for ; Mon, 20 Apr 2026 20:40:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1776710414; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=aMbR13c8I7W4CyhZ/3vdhASfNbiIUev0l3DpXlfWP64=; b=FU4P/QHlyj7Pf9CnUPVNHyoLwUHXQU5DZS8vg0BvItssW+0Jtp1gKcboLxSfQoZ1r0r6k5 NOj6atkE+jg72emj3t2930g7LkU7GRQ2jgGz9KY47x46c1adEl8nUAVs7uVf37ZbS2/9kl DkA6yjfFDGAwE7fVWnPKNlLCx2o2mog= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-76-50JmUzGLNraqIG55M5F94g-1; Mon, 20 Apr 2026 14:40:11 -0400 X-MC-Unique: 50JmUzGLNraqIG55M5F94g-1 X-Mimecast-MFC-AGG-ID: 50JmUzGLNraqIG55M5F94g_1776710410 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 75D5219560A3; Mon, 20 Apr 2026 18:40:10 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.48.16]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 645BC1800357; Mon, 20 Apr 2026 18:40:08 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Hans de Goede , Rick ten Wolde , Milan Zamazal Subject: [RFC PATCH v2 5/8] libcamera: shaders: Add LSC support Date: Mon, 20 Apr 2026 20:39:43 +0200 Message-ID: <20260420183949.110548-6-mzamazal@redhat.com> In-Reply-To: <20260420183949.110548-1-mzamazal@redhat.com> References: <20260420183949.110548-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: D8mSwy68doD1yvz1hWSqZCHy8BerTsKyVUWLtSxJPtE_1776710410 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" From: Xander Pronk Lens shading correction should be applied after black level subtraction (in order to make the computations with meaningful values) and before white balance (especially before white balance stats are computed). Note that lens shading correction depends on temperature, which depends on white balance, so there is a chicken-egg problem. Currently, we determine white balance and temperature from the preceding frame. TODO: It's unknown why the LSC is computed in the shader the way it is. Co-developed-by: Rick ten Wolde Signed-off-by: Rick ten Wolde Signed-off-by: Xander Pronk Signed-off-by: Milan Zamazal --- src/libcamera/shaders/bayer_1x_packed.frag | 8 ++++++++ src/libcamera/shaders/bayer_unpacked.frag | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag index 23747f78a..efc2fec72 100644 --- a/src/libcamera/shaders/bayer_1x_packed.frag +++ b/src/libcamera/shaders/bayer_1x_packed.frag @@ -70,6 +70,10 @@ uniform vec3 blacklevel; uniform float gamma; uniform float contrastExp; +#if defined(DO_LSC) +uniform sampler2D lsc_tex; +#endif + float apply_contrast(float value) { // Apply simple S-curve @@ -227,6 +231,10 @@ void main(void) rgb = rgb - blacklevel; + #if defined(DO_LSC) + rgb = rgb + rgb * 3.0 * texture2D(lsc_tex, textureOut).rgb; + #endif + /* * CCM is a 3x3 in the format * diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag index 1b85196ae..cc82e656c 100644 --- a/src/libcamera/shaders/bayer_unpacked.frag +++ b/src/libcamera/shaders/bayer_unpacked.frag @@ -29,6 +29,10 @@ uniform vec3 blacklevel; uniform float gamma; uniform float contrastExp; +#if defined(DO_LSC) +uniform sampler2D lsc_tex; +#endif + float apply_contrast(float value) { // Apply simple S-curve @@ -130,6 +134,10 @@ void main(void) { rgb = rgb - blacklevel; + #if defined(DO_LSC) + rgb = rgb + rgb * 3.0 * texture2D(lsc_tex, center.xy).rgb; + #endif + /* * CCM is a 3x3 in the format * From patchwork Mon Apr 20 18:39:44 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26526 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 C977DBDCBD for ; Mon, 20 Apr 2026 18:40:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8432F62EEF; Mon, 20 Apr 2026 20:40:18 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="Gg9wm3NT"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D022262EEF for ; Mon, 20 Apr 2026 20:40:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1776710414; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tGG/3sDD8prPLPiC/4iWGx+QFL+iFkSGB+ZJcJDQvk0=; b=Gg9wm3NTKEHieIhLGLqsdhrDVhupLrEklkf2IbSir1ZtVnEPpZ+0bLXmjuK3sAjwFhSs0G je+AfMHZ+InhNQVXOl4aFXSEzK6WzHyikQMuaxv2B9935Ai00P2EclpYdY43p15DM0b1r4 KZJP29RtSLnFGhpeAwVebkO6UCbYGPM= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-57-BQQD4NWFMo-TEB2nzgA1qw-1; Mon, 20 Apr 2026 14:40:13 -0400 X-MC-Unique: BQQD4NWFMo-TEB2nzgA1qw-1 X-Mimecast-MFC-AGG-ID: BQQD4NWFMo-TEB2nzgA1qw_1776710412 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 68AEC1956065; Mon, 20 Apr 2026 18:40:12 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.48.16]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EF2ED180057E; Mon, 20 Apr 2026 18:40:10 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Hans de Goede Subject: [RFC PATCH v2 6/8] libcamera: software_isp: Pass LSC availability to debayering Date: Mon, 20 Apr 2026 20:39:44 +0200 Message-ID: <20260420183949.110548-7-mzamazal@redhat.com> In-Reply-To: <20260420183949.110548-1-mzamazal@redhat.com> References: <20260420183949.110548-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: jXez5mrHex5EmwaxkJLBCXktLTxsWZA9WGXtvEk0H5E_1776710412 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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 algorithm may or may not be enabled in the tuning file. Debayering configuration needs this information to arrange things accordingly, e.g. to set up shader parameters. Let's add a corresponding flag that is set in the LSC algorithm (if present) and passed to Debayer::configure. This is similar to what we already do with CCM availability. The flag is ignored by CPU ISP, where LSC is not going to be implemented for now. Signed-off-by: Milan Zamazal --- include/libcamera/internal/software_isp/software_isp.h | 1 + include/libcamera/ipa/soft.mojom | 4 +++- src/ipa/simple/algorithms/lsc.cpp | 4 +++- src/ipa/simple/ipa_context.h | 1 + src/ipa/simple/soft_simple.cpp | 7 +++++-- src/libcamera/software_isp/debayer.cpp | 1 + src/libcamera/software_isp/debayer.h | 3 ++- src/libcamera/software_isp/debayer_cpu.cpp | 3 ++- src/libcamera/software_isp/debayer_cpu.h | 3 ++- src/libcamera/software_isp/debayer_egl.cpp | 5 ++++- src/libcamera/software_isp/debayer_egl.h | 4 +++- src/libcamera/software_isp/software_isp.cpp | 5 +++-- 12 files changed, 30 insertions(+), 11 deletions(-) diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h index 585e0d6d9..f9bda25bd 100644 --- a/include/libcamera/internal/software_isp/software_isp.h +++ b/include/libcamera/internal/software_isp/software_isp.h @@ -100,6 +100,7 @@ private: DebayerParams debayerParams_; DmaBufAllocator dmaHeap_; bool ccmEnabled_; + bool lscEnabled_; std::unique_ptr ipa_; std::deque queuedInputBuffers_; diff --git a/include/libcamera/ipa/soft.mojom b/include/libcamera/ipa/soft.mojom index 77328c5fd..aaefd50c4 100644 --- a/include/libcamera/ipa/soft.mojom +++ b/include/libcamera/ipa/soft.mojom @@ -18,7 +18,9 @@ interface IPASoftInterface { libcamera.SharedFD fdParams, libcamera.IPACameraSensorInfo sensorInfo, libcamera.ControlInfoMap sensorControls) - => (int32 ret, libcamera.ControlInfoMap ipaControls, bool ccmEnabled); + => (int32 ret, + libcamera.ControlInfoMap ipaControls, + bool ccmEnabled, bool lscEnabled); start() => (int32 ret); stop(); configure(IPAConfigInfo configInfo) diff --git a/src/ipa/simple/algorithms/lsc.cpp b/src/ipa/simple/algorithms/lsc.cpp index 9588dc95d..e52a766d2 100644 --- a/src/ipa/simple/algorithms/lsc.cpp +++ b/src/ipa/simple/algorithms/lsc.cpp @@ -15,7 +15,7 @@ namespace ipa::soft::algorithms { LOG_DEFINE_CATEGORY(IPASoftLsc) -int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) +int Lsc::init(IPAContext &context, const YamlObject &tuningData) { int ret_r = lscR.readYaml(tuningData["grids"], "ct", "r"); int ret_g = lscG.readYaml(tuningData["grids"], "ct", "g"); @@ -27,6 +27,8 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData return -EINVAL; } + context.lscEnabled = true; + return 0; } diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h index c4bd91bb0..d77bbc280 100644 --- a/src/ipa/simple/ipa_context.h +++ b/src/ipa/simple/ipa_context.h @@ -93,6 +93,7 @@ struct IPAContext { FCQueue frameContexts; ControlInfoMap::Map ctrlMap; bool ccmEnabled = false; + bool lscEnabled = false; }; } /* namespace ipa::soft */ diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp index 7d25bdd26..8c7e71b22 100644 --- a/src/ipa/simple/soft_simple.cpp +++ b/src/ipa/simple/soft_simple.cpp @@ -57,7 +57,8 @@ public: const IPACameraSensorInfo &sensorInfo, const ControlInfoMap &sensorControls, ControlInfoMap *ipaControls, - bool *ccmEnabled) override; + bool *ccmEnabled, + bool *lscEnabled) override; int configure(const IPAConfigInfo &configInfo) override; int start() override; @@ -97,7 +98,8 @@ int IPASoftSimple::init(const IPASettings &settings, const IPACameraSensorInfo &sensorInfo, const ControlInfoMap &sensorControls, ControlInfoMap *ipaControls, - bool *ccmEnabled) + bool *ccmEnabled, + bool *lscEnabled) { camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel); if (!camHelper_) { @@ -136,6 +138,7 @@ int IPASoftSimple::init(const IPASettings &settings, return ret; *ccmEnabled = context_.ccmEnabled; + *lscEnabled = context_.lscEnabled; params_ = nullptr; stats_ = nullptr; diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index b60ebcd9b..edfe313c0 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -91,6 +91,7 @@ Debayer::~Debayer() * \param[in] inputCfg The input configuration * \param[in] outputCfgs The output configurations * \param[in] ccmEnabled Whether a color correction matrix is applied + * \param[in] lscEnabled Whether lens shading correction grid is provided * * \return 0 on success, a negative errno on failure */ diff --git a/src/libcamera/software_isp/debayer.h b/src/libcamera/software_isp/debayer.h index ea1ec6dcf..32ffc26f6 100644 --- a/src/libcamera/software_isp/debayer.h +++ b/src/libcamera/software_isp/debayer.h @@ -40,7 +40,8 @@ public: virtual int configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, - bool ccmEnabled) = 0; + bool ccmEnabled, + bool lscEnabled) = 0; virtual std::vector formats(PixelFormat inputFormat) = 0; diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp index dd0fff871..b9656da0a 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -541,7 +541,8 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, int DebayerCpu::configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, - bool ccmEnabled) + bool ccmEnabled, + [[maybe_unused]] bool lscEnabled) { if (getInputConfig(inputCfg.pixelFormat, inputConfig_) != 0) return -EINVAL; diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h index 05fecc8fe..f3be1222d 100644 --- a/src/libcamera/software_isp/debayer_cpu.h +++ b/src/libcamera/software_isp/debayer_cpu.h @@ -36,7 +36,8 @@ public: int configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, - bool ccmEnabled); + bool ccmEnabled, + bool lscEnabled); Size patternSize(PixelFormat inputFormat); std::vector formats(PixelFormat input); std::tuple diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 08e513eaf..399915164 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -278,7 +278,8 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm int DebayerEGL::configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, - [[maybe_unused]] bool ccmEnabled) + [[maybe_unused]] bool ccmEnabled, + bool lscEnabled) { if (getInputConfig(inputCfg.pixelFormat, inputConfig_) != 0) return -EINVAL; @@ -295,6 +296,8 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg, return -EINVAL; } + lscEnabled_ = lscEnabled; + inputConfig_.stride = inputCfg.stride; inputPixelFormat_ = inputCfg.pixelFormat; width_ = inputCfg.size.width; diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index bdde676f2..f96077af5 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -43,7 +43,8 @@ public: int configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, - bool ccmEnabled); + bool ccmEnabled, + bool lscEnabled); Size patternSize(PixelFormat inputFormat); @@ -84,6 +85,7 @@ private: std::unique_ptr eglImageBayerIn_; std::unique_ptr eglImageBayerOut_; + bool lscEnabled_; /* Shader parameters */ float firstRed_x_; float firstRed_y_; diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index 60228369f..798a06969 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -155,7 +155,8 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, sensorInfo, sensor->controls(), ipaControls, - &ccmEnabled_); + &ccmEnabled_, + &lscEnabled_); if (ret) { LOG(SoftwareIsp, Error) << "IPA init failed"; debayer_.reset(); @@ -271,7 +272,7 @@ int SoftwareIsp::configure(const StreamConfiguration &inputCfg, if (ret < 0) return ret; - ret = debayer_->configure(inputCfg, outputCfgs, ccmEnabled_); + ret = debayer_->configure(inputCfg, outputCfgs, ccmEnabled_, lscEnabled_); if (ret < 0) return ret; From patchwork Mon Apr 20 18:39:45 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26528 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 0FC7DBDCBD for ; Mon, 20 Apr 2026 18:40:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BBE1062EF7; Mon, 20 Apr 2026 20:40:21 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="SwLZWOfT"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5C8B262EF3 for ; Mon, 20 Apr 2026 20:40:19 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1776710417; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3ppH+azBFu0bos5jf4k4gpbTKyVtdcdC8mOKHIIZw4s=; b=SwLZWOfTe223EIgRWfojQaRJKaa7cPjj50Vco3+CeMqAMtW8DdOTJZtKsCsf/VMann27mV JplNEEc2jOoLUAW8oo1kSb1YNROowKLyX4Hy4oC5RTdHLuJpNASn86xfOd/8zxeVYTsHfa dGIOriUjRctUm2vSf2hHhXLusl/i718= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-156-83lSNLp8O02asFWiUNZMkA-1; Mon, 20 Apr 2026 14:40:16 -0400 X-MC-Unique: 83lSNLp8O02asFWiUNZMkA-1 X-Mimecast-MFC-AGG-ID: 83lSNLp8O02asFWiUNZMkA_1776710415 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 16D491956095; Mon, 20 Apr 2026 18:40:15 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.48.16]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 02EC4180047F; Mon, 20 Apr 2026 18:40:12 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Hans de Goede , Rick ten Wolde , Milan Zamazal Subject: [RFC PATCH v2 7/8] libcamera: software_isp: debayer_egl: Add LSC support Date: Mon, 20 Apr 2026 20:39:45 +0200 Message-ID: <20260420183949.110548-8-mzamazal@redhat.com> In-Reply-To: <20260420183949.110548-1-mzamazal@redhat.com> References: <20260420183949.110548-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: pufnuvyGW9DOg1b43nbZiAoMHHJ_9vhqd5mVvMQbSWA_1776710415 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" From: Xander Pronk Add support for passing the LSC table from debayerParams to the shaders. Co-developed-by: Rick ten Wolde Signed-off-by: Rick ten Wolde Signed-off-by: Xander Pronk Signed-off-by: Milan Zamazal --- src/libcamera/software_isp/debayer_egl.cpp | 22 +++++++++++++++++++++- src/libcamera/software_isp/debayer_egl.h | 5 +++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 399915164..301dfc1c6 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -111,6 +111,9 @@ int DebayerEGL::getShaderVariableLocations(void) textureUniformBayerFirstRed_ = glGetUniformLocation(programId_, "tex_bayer_first_red"); textureUniformProjMatrix_ = glGetUniformLocation(programId_, "proj_matrix"); + if (lscEnabled_) + textureUniformLsc_ = glGetUniformLocation(programId_, "lsc_tex"); + LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_ << " tex_y " << textureUniformBayerDataIn_ << " ccm " << ccmUniformDataIn_ @@ -121,7 +124,8 @@ int DebayerEGL::getShaderVariableLocations(void) << " tex_size " << textureUniformSize_ << " stride_factor " << textureUniformStrideFactor_ << " tex_bayer_first_red " << textureUniformBayerFirstRed_ - << " proj_matrix " << textureUniformProjMatrix_; + << " proj_matrix " << textureUniformProjMatrix_ + << " lsc " << (lscEnabled_ ? textureUniformLsc_ : -1); return 0; } @@ -140,6 +144,9 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm /* Specify GL_OES_EGL_image_external */ egl_.pushEnv(shaderEnv, "#extension GL_OES_EGL_image_external: enable"); + if (lscEnabled_) + egl_.pushEnv(shaderEnv, "#define DO_LSC"); + /* * Tell shaders how to re-order output taking account of how the pixels * are actually stored by EGL. @@ -339,6 +346,12 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg, */ stats_->setWindow(Rectangle(window_.size())); + if (lscEnabled_) { + constexpr unsigned int gridSize = DebayerParams::kLscGridSize; + eglImageLscLookup_ = + std::make_unique(gridSize, gridSize, gridSize * 3, GL_TEXTURE2, 2); + } + return 0; } @@ -478,6 +491,13 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams ¶ms) glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm); LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.combinedMatrix; + if (lscEnabled_) { + egl_.createTexture2D(*eglImageLscLookup_, GL_RGB, + DebayerParams::kLscGridSize, DebayerParams::kLscGridSize, + params.lscLut.data(), GL_LINEAR); + glUniform1i(textureUniformLsc_, eglImageLscLookup_->texture_unit_uniform_id_); + } + /* * 0 = Red, 1 = Green, 2 = Blue */ diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index f96077af5..38271a316 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -85,7 +85,10 @@ private: std::unique_ptr eglImageBayerIn_; std::unique_ptr eglImageBayerOut_; + /* LSC lookup table */ + std::unique_ptr eglImageLscLookup_; bool lscEnabled_; + /* Shader parameters */ float firstRed_x_; float firstRed_y_; @@ -99,6 +102,8 @@ private: GLint textureUniformBayerDataIn_; + GLint textureUniformLsc_; + /* Represent per-frame CCM as a uniform vector of floats 3 x 3 */ GLint ccmUniformDataIn_; From patchwork Mon Apr 20 18:39:46 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26529 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 A3421BDCBD for ; Mon, 20 Apr 2026 18:40:23 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 55A0062EFD; Mon, 20 Apr 2026 20:40:23 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="dTI8PA4Q"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B97D762EF6 for ; Mon, 20 Apr 2026 20:40:21 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1776710420; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9sWLN5zFsvsjo7uIP+VvJtokKl+xHqKEhtQ8BXwskRc=; b=dTI8PA4QpXfX2Q5eNDfhVefI1+VakYln35SKeeHYg3Gn3CazS8xYk6iuRIx0cerk3CsuPW 8e3/WMo/HX6/YyW6XpIEmC4FK6Xmtr4x8zURfoVIEF9Lcwpsmbprde5leEbrCB/pRf8k1u UvgVCy/PVdCcxLlpPzUAE+LCz5ZPBTM= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-616-Haj7pC93PJq8vKSs1TiTmg-1; Mon, 20 Apr 2026 14:40:18 -0400 X-MC-Unique: Haj7pC93PJq8vKSs1TiTmg-1 X-Mimecast-MFC-AGG-ID: Haj7pC93PJq8vKSs1TiTmg_1776710417 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B7C22180036E; Mon, 20 Apr 2026 18:40:17 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.48.16]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A6221180047F; Mon, 20 Apr 2026 18:40:15 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Derek Gielen , Hans de Goede , Aron Dosti , Milan Zamazal Subject: [RFC PATCH v2 8/8] utils/tuning: Add LSC scripts Date: Mon, 20 Apr 2026 20:39:46 +0200 Message-ID: <20260420183949.110548-9-mzamazal@redhat.com> In-Reply-To: <20260420183949.110548-1-mzamazal@redhat.com> References: <20260420183949.110548-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: JF6LWjGlCD4v81BBJbogK3USnkbeD4Fjyox4OLikmJQ_1776710417 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" From: Derek Gielen Add script for the conversion of the tuning file to a format usable by the lens shading correction shader. Add script for visualizing the lens shading correction using pyplot. Co-developed-by: Aron Dosti Signed-off-by: Aron Dosti Signed-off-by: Derek Gielen Signed-off-by: Milan Zamazal --- utils/tuning/exportTuningToLscShader.py | 120 ++++++++++++++++++++++++ utils/tuning/generate_lsc_map_plot.py | 76 +++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 utils/tuning/exportTuningToLscShader.py create mode 100644 utils/tuning/generate_lsc_map_plot.py diff --git a/utils/tuning/exportTuningToLscShader.py b/utils/tuning/exportTuningToLscShader.py new file mode 100644 index 000000000..60bc37ec2 --- /dev/null +++ b/utils/tuning/exportTuningToLscShader.py @@ -0,0 +1,120 @@ +import yaml +import numpy as np +import argparse +import sys + +# --- Configuration --- +GRID_W = 16 +GRID_H = 16 + +# Formula constants +BLACK_LEVEL = 1024.0 +SCALE_FACTOR = 3071 # Divisor to map the range to 0-255 + +def load_and_process_yaml(input_filename, target_ct): + # 1. Load the YAML file + try: + with open(input_filename, 'r') as f: + data = yaml.safe_load(f) + except FileNotFoundError: + print(f"Error: Input file '{input_filename}' not found.") + return None, None, None + + # 2. Find the LensShadingCorrection block + lsc_data = None + for algo in data['algorithms']: + if 'LensShadingCorrection' in algo: + lsc_data = algo['LensShadingCorrection'] + break + + if not lsc_data: + print("Error: LensShadingCorrection block not found.") + return None, None, None + + # 3. Extract the set for the specific Color Temperature (CT) provided in arguments + sets = lsc_data['sets'] + target_set = next((item for item in sets if item['ct'] == target_ct), None) + + if not target_set: + print(f"Error: Set for Color Temperature {target_ct} not found in '{input_filename}'.") + return None, None, None + + print(f"Found data for CT {target_ct}. Applying formula: (x - {int(BLACK_LEVEL)}) / {SCALE_FACTOR} ...") + + # 4. Get Raw Data + r_raw = np.array(target_set['r']) + b_raw = np.array(target_set['b']) + gr_raw = np.array(target_set['gr']) + gb_raw = np.array(target_set['gb']) + + # Calculate Green Channel (Average of GR and GB) + g_raw = (gr_raw + gb_raw) / 2.0 + + # 5. Define the calculation logic + def apply_formula(data_array): + """ + Applies the specific user formula: + 1. Subtract Black Level (1024) + 2. Divide by the Scale Factor (3071) + 3. Multiply by 255 and convert to integer + """ + result = ((data_array - BLACK_LEVEL) / SCALE_FACTOR) * 255 + return result.astype(int) + + # 6. Apply calculation to all channels + r_final = apply_formula(r_raw) + g_final = apply_formula(g_raw) + b_final = apply_formula(b_raw) + + return r_final, g_final, b_final + +def save_custom_grid_yaml(output_filename, r, g, b, target_ct): + + # Helper function to format the array as a visual grid string + def format_array_as_grid_string(arr): + lines = [] + # Loop through the array in chunks of 16 (GRID_W) + for i in range(0, len(arr), GRID_W): + row = arr[i:i + GRID_W] + # Join numbers with commas + row_str = ", ".join(map(str, row)) + lines.append(f" {row_str}") + # Wrap in brackets to form a valid YAML list, but visually formatted + return "[\n" + ",\n".join(lines) + "\n ]" + + # Write the file manually to ensure specific formatting + with open(output_filename, 'w') as f: + f.write(f"description: 'LSC Fixed Formula ((x-{int(BLACK_LEVEL)})/{SCALE_FACTOR})'\n") + f.write(f"source_ct: {target_ct}\n") + f.write(f"grid_size: [{GRID_W}, {GRID_H}]\n") + f.write(f"formula_used: '(RawValue - {int(BLACK_LEVEL)}) / {SCALE_FACTOR} -> [0..255]'\n") + f.write(f"channels:\n") + + f.write(" red: " + format_array_as_grid_string(r) + "\n") + f.write(" green: " + format_array_as_grid_string(g) + "\n") + f.write(" blue: " + format_array_as_grid_string(b) + "\n") + + print(f"Success! Saved formatted grid to '{output_filename}'") + +# --- Main Execution --- +if __name__ == "__main__": + # 1. Setup Argument Parser + parser = argparse.ArgumentParser(description="Convert LSC YAML data to shader grid format.") + parser.add_argument("ct", type=int, help="The Color Temperature to process (e.g. 2700, 5000, 6500)") + + # 2. Parse arguments + args = parser.parse_args() + ct_val = args.ct + + # 3. Construct filenames based on the CT value + # Assumes input file is named 'tuning_XXXX.yaml' + input_file = f'tuning{ct_val}.yaml' + output_file = f'lsc_shader_16x16_{ct_val}_fixed.yaml' + + print(f"--- Processing for Color Temp: {ct_val} ---") + + # 4. Run Process + r, g, b = load_and_process_yaml(input_file, ct_val) + + if r is not None: + save_custom_grid_yaml(output_file, r, g, b, ct_val) diff --git a/utils/tuning/generate_lsc_map_plot.py b/utils/tuning/generate_lsc_map_plot.py new file mode 100644 index 000000000..7a0aaeb8a --- /dev/null +++ b/utils/tuning/generate_lsc_map_plot.py @@ -0,0 +1,76 @@ +import yaml +import numpy as np +import matplotlib.pyplot as plt + +# 1. Load the data +try: + with open('tuning2700.yaml', 'r') as f: + data = yaml.safe_load(f) +except FileNotFoundError: + print("Error: 'tuning.yaml' not found. Please ensure the file exists.") + exit() + +# 2. Find LensShadingCorrection safely +lsc_data = None +for algo in data['algorithms']: + if 'LensShadingCorrection' in algo: + lsc_data = algo['LensShadingCorrection'] + break + +if not lsc_data: + print("Error: LensShadingCorrection block not found in YAML.") + exit() + +# 3. Extract the set for disirable Kelvin +kelvin = 2700 +sets = lsc_data['sets'] +target_set = next((item for item in sets if item['ct'] == kelvin), None) + +if not target_set: + print("Error: CT 6500 not found in sets.") + exit() + +# 4. Get lists and normalize (1024 = 1.0 gain) +r_list = np.array(target_set['r']) +gr_list = np.array(target_set['gr']) +gb_list = np.array(target_set['gb']) +b_list = np.array(target_set['b']) + +r_norm = r_list / 1024.0 +b_norm = b_list / 1024.0 +# Average the two greens for the shader +g_norm = (gr_list + gb_list) / 2.0 / 1024.0 + +# 5. Reshape into 17x17 Grids +grid_size = (17, 17) +r_grid = r_norm.reshape(grid_size) +g_grid = g_norm.reshape(grid_size) +b_grid = b_norm.reshape(grid_size) + +# 6. Visualization +# We create 3 separate plots to see the data distribution correctly +fig, axs = plt.subplots(1, 3, figsize=(15, 5)) + +# Plot Red +im1 = axs[0].imshow(r_grid, cmap='viridis') +axs[0].set_title('Red Gain Map') +fig.colorbar(im1, ax=axs[0]) + +# Plot Green +im2 = axs[1].imshow(g_grid, cmap='viridis') +axs[1].set_title('Green Gain Map') +fig.colorbar(im2, ax=axs[1]) + +# Plot Blue +im3 = axs[2].imshow(b_grid, cmap='viridis') +axs[2].set_title('Blue Gain Map') +fig.colorbar(im3, ax=axs[2]) + +plt.suptitle(f"LSC Gain Maps (Center ~1.0, Corners > 1.0) for collor temprature {kelvin}") +plt.show() + +# 7. Prepare Texture for Export (Optional) +# Stack them for your shader: (17, 17, 3) +lsc_texture = np.dstack((r_grid, g_grid, b_grid)) +print(f"Final Texture Shape: {lsc_texture.shape}") +print(f"Sample Blue Value at Corner: {b_grid[0, 0]}")