From patchwork Fri Apr 24 20:02:50 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26564 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 2419FBE173 for ; Fri, 24 Apr 2026 20:03:24 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D5C8562FB0; Fri, 24 Apr 2026 22:03:23 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="TCvaDTr+"; 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 F128B62E6A for ; Fri, 24 Apr 2026 22:03:21 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777061000; 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=DIGVeJ4bqKpKRKJEA8DvJ0QJ41ZIivpKRCLH3IYu/XA=; b=TCvaDTr+ivJPTUbQN6xhWjD7aZaslLddn15vl77tIYJqnfckfLBFm/+Vg6zCHJu7C6OrM8 wihiVNrcbXEerWazE4ErF4v9lcigoXi+UP0/TbbdoYOaRjGFyTDVljnN8E/C9s/4GYOs/A 8HGWGkhOqKqNQG/6k8jGzChB/CVf+n8= 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-561-zDyhLaQDNEyuhoxACZ4uCQ-1; Fri, 24 Apr 2026 16:03:17 -0400 X-MC-Unique: zDyhLaQDNEyuhoxACZ4uCQ-1 X-Mimecast-MFC-AGG-ID: zDyhLaQDNEyuhoxACZ4uCQ_1777060994 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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 E274518005A9; Fri, 24 Apr 2026 20:03:13 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.32.33]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B8ACF3007572; Fri, 24 Apr 2026 20:03:11 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Bryan O'Donoghue , Hans de Goede , Rick ten Wolde , Milan Zamazal Subject: [RFC PATCH v3 4/7] ipa: simple: Add LSC algorithm Date: Fri, 24 Apr 2026 22:02:50 +0200 Message-ID: <20260424200255.356798-5-mzamazal@redhat.com> In-Reply-To: <20260424200255.356798-1-mzamazal@redhat.com> References: <20260424200255.356798-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: LFReHKQBc-uLY5numqWNt71sn_GQ8Wdn3XVdra8K_Y0_1777060994 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 as multiplication factors for each of the RGB colours. The interpolated grid is transformed to an array to be used as an RGB texture in debayering. The floating point multiplication factors specified in the tuning file are converted to bytes, from 1.0..4.0 range (values outside this range are clamped) to 0..255 range. This is to make the table smaller and avoiding dealing with floating point textures (for no better reason that we already use byte textures and know how to do it). 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 | 79 +++++++++++++++++++++++++++ src/ipa/simple/algorithms/lsc.h | 41 ++++++++++++++ src/ipa/simple/algorithms/meson.build | 1 + 3 files changed, 121 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..585957e74 --- /dev/null +++ b/src/ipa/simple/algorithms/lsc.cpp @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Lens shading correction + */ + +#include "lsc.h" + +#include +#include + +#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); + + /* + * The constructed table is compressed by converting from floats to bytes. + * This makes the texture uploaded to a GPU smaller and we don't have to + * deal with textures containing float values. + * The byte range 0..255 represents floating point values 1.0..4.0. Values + * outside this range are clamped. When accessed in the shader, the byte + * range is represented by 0.0..1.0 range. Then the resulting pixel value + * can be computed as + * rgb + rgb * 3.0 * LUT_VALUE + */ + DebayerParams::LscLookupTable lut; + constexpr unsigned int gridSize = DebayerParams::kLscGridSize; + auto float2byte = [](float factor) -> uint8_t { + return std::round((std::clamp(factor, 1.0f, 4.0f) - 1.0) / 3.0 * 255); + }; + for (unsigned int i = 0, j = 0; i < gridSize * gridSize; i++) { + lut[j++] = float2byte(matrixR.data()[i]); + lut[j++] = float2byte(matrixG.data()[i]); + lut[j++] = float2byte(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..ef3474aec --- /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', ])