From patchwork Sun Aug 16 20:42:57 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Alexander X-Patchwork-Id: 27775 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 CD8C9C3308 for ; Mon, 17 Aug 2026 07:30:14 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7C4396819F; Mon, 17 Aug 2026 09:30:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=inspiredexperts.com header.i=@inspiredexperts.com header.b="B5Adp4Zc"; dkim-atps=neutral Received: from s1.inspiredexperts.com (s1.inspiredexperts.com [162.243.156.162]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 75AEC6819C for ; Sun, 16 Aug 2026 22:43:03 +0200 (CEST) Received: from localhost (s1.inspiredexperts.com [127.0.0.1]) by s1.inspiredexperts.com (Postfix) with ESMTP id 55209D2D699 for ; Sun, 16 Aug 2026 14:43:00 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=inspiredexperts.com; s=default; t=1786912981; bh=QwIf2eZbr8ya+vN+Juvm2CPrjnVewplyNOaJdXWnhfg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=B5Adp4ZcjcTG11uL7o8HdY7DXOa/cW26achuGIjICjH7b+bilpoKxpXdfGwLO+qGd uj4S1TiA8ap30zVkiSpzbxkKJnu3Ex+PTLoXrqIZpy92clDGkL9CvzBXPMs5b3uawM AxmdUL3mO2+278XQit5zlKA7F8xy1MUH+m+BDB/A= From: James Alexander To: libcamera-devel@lists.libcamera.org Subject: [PATCH 1/3] ipa: simple: adjust: Read defaults from tuning Date: Sun, 16 Aug 2026 14:42:57 -0600 Message-ID: <20260816204259.2845517-2-opensource@inspiredexperts.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260816204259.2845517-1-opensource@inspiredexperts.com> References: <20260816204259.2845517-1-opensource@inspiredexperts.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on s1.inspiredexperts.com X-Mailman-Approved-At: Mon, 17 Aug 2026 09:30:05 +0200 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" Simple IPA tuning files can enable Adjust, but they cannot choose the starting gamma, contrast or saturation. That leaves sensor-specific tuning unable to set useful defaults without application controls. Read optional values from the Adjust section, clamp them to the existing control ranges and use them as both control defaults and initial state. Existing tuning files keep the current defaults. Build-tested against libcamera base b8910c9a4961 and hardware-tested as part of the complete patch set on the target HP Spectre. Signed-off-by: James Alexander diff --git a/src/ipa/simple/algorithms/adjust.cpp b/src/ipa/simple/algorithms/adjust.cpp index 8bf39c4..be29127 100644 --- a/src/ipa/simple/algorithms/adjust.cpp +++ b/src/ipa/simple/algorithms/adjust.cpp @@ -24,24 +24,38 @@ constexpr float kDefaultSaturation = 1.0f; LOG_DEFINE_CATEGORY(IPASoftAdjust) -int Adjust::init(IPAContext &context, [[maybe_unused]] const ValueNode &tuningData) +int Adjust::init(IPAContext &context, const ValueNode &tuningData) { + auto gamma = tuningData["gamma"].get(); + if (gamma.has_value()) + defaultGamma_ = std::clamp(gamma.value(), 0.1f, 10.0f); + + auto contrast = tuningData["contrast"].get(); + if (contrast.has_value()) + defaultContrast_ = std::clamp(contrast.value(), 0.0f, 2.0f); + + auto saturation = tuningData["saturation"].get(); + if (saturation.has_value()) + defaultSaturation_ = std::clamp(saturation.value(), 0.0f, 2.0f); + context.ctrlMap[&controls::Gamma] = - ControlInfo(0.1f, 10.0f, kDefaultGamma); + ControlInfo(0.1f, 10.0f, defaultGamma_); context.ctrlMap[&controls::Contrast] = - ControlInfo(0.0f, 2.0f, kDefaultContrast); + ControlInfo(0.0f, 2.0f, defaultContrast_); if (context.ccmEnabled) context.ctrlMap[&controls::Saturation] = - ControlInfo(0.0f, 2.0f, kDefaultSaturation); + ControlInfo(0.0f, 2.0f, defaultSaturation_); return 0; } int Adjust::configure(IPAContext &context, [[maybe_unused]] const IPAConfigInfo &configInfo) { - context.activeState.knobs.gamma = kDefaultGamma; - context.activeState.knobs.contrast = std::optional(); + context.activeState.knobs.gamma = defaultGamma_; + context.activeState.knobs.contrast = defaultContrast_; context.activeState.knobs.saturation = std::optional(); + if (context.ccmEnabled) + context.activeState.knobs.saturation = defaultSaturation_; return 0; } diff --git a/src/ipa/simple/algorithms/adjust.h b/src/ipa/simple/algorithms/adjust.h index 49c1f26..1968b7c 100644 --- a/src/ipa/simple/algorithms/adjust.h +++ b/src/ipa/simple/algorithms/adjust.h @@ -7,6 +7,8 @@ #pragma once +#include + #include "libcamera/internal/matrix.h" #include @@ -43,6 +45,10 @@ public: private: void applySaturation(Matrix &ccm, float saturation); + + float defaultGamma_ = kDefaultGamma; + float defaultContrast_ = 1.0f; + float defaultSaturation_ = 1.0f; }; } /* namespace ipa::soft::algorithms */ From patchwork Sun Aug 16 20:42:58 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Alexander X-Patchwork-Id: 27776 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 0D8F1C330A for ; Mon, 17 Aug 2026 07:30:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E134068240; Mon, 17 Aug 2026 09:30:11 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=inspiredexperts.com header.i=@inspiredexperts.com header.b="PahA/MyF"; dkim-atps=neutral Received: from s1.inspiredexperts.com (s1.inspiredexperts.com [162.243.156.162]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D150F681A0 for ; Sun, 16 Aug 2026 22:43:03 +0200 (CEST) Received: from localhost (s1.inspiredexperts.com [127.0.0.1]) by s1.inspiredexperts.com (Postfix) with ESMTP id 16BD9D2D68C for ; Sun, 16 Aug 2026 14:43:02 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=inspiredexperts.com; s=default; t=1786912982; bh=mZ0djEnBvYwYaU5LEsqFV1XVqm6JpEK8MX0tQ962dYU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=PahA/MyFwSvkUOhg42StBg/FzlW3J/E9Cv3oojjce6wp7UC3UD10RwanDk5SasRrH j1sB7qU3WRtcGiv2z4QScylmdRPD7X6Uh8QtHLMgnINaUTrDLuIu+HYkdbXcEMSxlh wBhuyt/Dh3cWjBOHxhhyuOtcmbl9PvwKSzRnjEcQ= From: James Alexander To: libcamera-devel@lists.libcamera.org Subject: [PATCH 2/3] ipa: simple: agc: Read limits from tuning Date: Sun, 16 Aug 2026 14:42:58 -0600 Message-ID: <20260816204259.2845517-3-opensource@inspiredexperts.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260816204259.2845517-1-opensource@inspiredexperts.com> References: <20260816204259.2845517-1-opensource@inspiredexperts.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on s1.inspiredexperts.com X-Mailman-Approved-At: Mon, 17 Aug 2026 09:30:05 +0200 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 simple IPA AGC currently uses one target and the full exposure and gain ranges reported by the sensor. On the tested ov08x40 setup that produced more noise and longer exposures than were useful for a webcam. Allow tuning to set the histogram target, maximum analogue gain and maximum exposure time. Missing values preserve the current behaviour, and configured limits are clamped to the sensor's reported range. Build-tested against libcamera base b8910c9a4961 and hardware-tested as part of the complete patch set on the target HP Spectre. Signed-off-by: James Alexander diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp index a13a755..fa93d03 100644 --- a/src/ipa/simple/algorithms/agc.cpp +++ b/src/ipa/simple/algorithms/agc.cpp @@ -8,6 +8,7 @@ #include "agc.h" #include +#include #include #include @@ -15,6 +16,8 @@ #include "control_ids.h" +using namespace std::literals::chrono_literals; + namespace libcamera { LOG_DEFINE_CATEGORY(IPASoftExposure) @@ -62,7 +65,46 @@ static constexpr float kExpProportionalGain = 0.04; static constexpr float kExpMaxStep = 0.15; Agc::Agc() + : exposureOptimal_(kExposureOptimal) +{ +} + +int Agc::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) +{ + auto target = tuningData["target"].get(); + if (target.has_value()) + exposureOptimal_ = std::clamp(target.value(), 1.0, 5.0); + + auto maxAnalogueGain = tuningData["maxAnalogueGain"].get(); + if (maxAnalogueGain.has_value()) + maxAnalogueGain_ = std::max(1.0, maxAnalogueGain.value()); + + auto maxExposureTimeMs = tuningData["maxExposureTimeMs"].get(); + if (maxExposureTimeMs.has_value()) + maxExposureTimeMs_ = std::max(1.0, maxExposureTimeMs.value()); + + return 0; +} + +int Agc::configure(IPAContext &context, + [[maybe_unused]] const IPAConfigInfo &configInfo) { + if (maxAnalogueGain_.has_value()) + context.configuration.agc.againMax = + std::clamp(maxAnalogueGain_.value(), + context.configuration.agc.againMin, + context.configuration.agc.againMax); + + if (maxExposureTimeMs_.has_value()) { + utils::Duration maxExposure = maxExposureTimeMs_.value() * 1.0ms; + int32_t maxExposureLines = + std::max(context.configuration.agc.exposureMin, + maxExposure / context.configuration.agc.lineDuration); + context.configuration.agc.exposureMax = + std::min(context.configuration.agc.exposureMax, maxExposureLines); + } + + return 0; } void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV) @@ -70,7 +112,7 @@ void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, dou int32_t &exposure = frameContext.sensor.exposure; double &again = frameContext.sensor.gain; - double error = kExposureOptimal - exposureMSV; + double error = exposureOptimal_ - exposureMSV; if (std::abs(error) <= kExposureSatisfactory) return; diff --git a/src/ipa/simple/algorithms/agc.h b/src/ipa/simple/algorithms/agc.h index 112d9f5..501252f 100644 --- a/src/ipa/simple/algorithms/agc.h +++ b/src/ipa/simple/algorithms/agc.h @@ -7,6 +7,8 @@ #pragma once +#include + #include "algorithm.h" namespace libcamera { @@ -19,6 +21,9 @@ public: Agc(); ~Agc() = default; + int init(IPAContext &context, const ValueNode &tuningData) override; + int configure(IPAContext &context, + const IPAConfigInfo &configInfo) override; void process(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, const SwIspStats *stats, @@ -26,6 +31,10 @@ public: private: void updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV); + + double exposureOptimal_; + std::optional maxAnalogueGain_; + std::optional maxExposureTimeMs_; }; } /* namespace ipa::soft::algorithms */ From patchwork Sun Aug 16 20:42:59 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Alexander X-Patchwork-Id: 27777 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 A8FF5C3303 for ; Mon, 17 Aug 2026 07:30:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0150D681A2; Mon, 17 Aug 2026 09:30:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=inspiredexperts.com header.i=@inspiredexperts.com header.b="OeS1sjc6"; dkim-atps=neutral Received: from s1.inspiredexperts.com (s1.inspiredexperts.com [162.243.156.162]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3D82A6819C for ; Sun, 16 Aug 2026 22:43:04 +0200 (CEST) Received: from localhost (s1.inspiredexperts.com [127.0.0.1]) by s1.inspiredexperts.com (Postfix) with ESMTP id 949B6D2D68D for ; Sun, 16 Aug 2026 14:43:02 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=inspiredexperts.com; s=default; t=1786912982; bh=i1mjAgpSe74lM7Bvaruifs5jKsDxF4vUiWac9PJ4bD0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=OeS1sjc61wDOW2mTEETiqCkmwpQT/2HDD4xTGX4ka98eBsR5Bavu1zg2VHk6u/wwF ERD7Q6BSJNpyhYzkveZFo5z3JT3j90fWVPU8ISJP5lMaj9p/mPQDBTY8Fn30tNJkVW 3UJogF3vqPMvEuPrnPg5Tfvku5sVUpdEFAGqskSE= From: James Alexander To: libcamera-devel@lists.libcamera.org Subject: [PATCH 3/3] ipa: simple: Add OV08X40 tuning Date: Sun, 16 Aug 2026 14:42:59 -0600 Message-ID: <20260816204259.2845517-4-opensource@inspiredexperts.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260816204259.2845517-1-opensource@inspiredexperts.com> References: <20260816204259.2845517-1-opensource@inspiredexperts.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on s1.inspiredexperts.com X-Mailman-Approved-At: Mon, 17 Aug 2026 09:30:05 +0200 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 the ov08x40 tuning used on the HP Spectre test system and install it with the other simple IPA data. The matrix and image controls reduce a green-yellow cast and keep webcam exposure and gain within practical limits on that machine. The tuning was tested under warm indoor lighting but is not lab calibrated. Build-tested against libcamera base b8910c9a4961 and hardware-tested as part of the complete patch set on the target HP Spectre. Signed-off-by: James Alexander diff --git a/src/ipa/simple/data/meson.build b/src/ipa/simple/data/meson.build index 92795ee..d994100 100644 --- a/src/ipa/simple/data/meson.build +++ b/src/ipa/simple/data/meson.build @@ -1,6 +1,7 @@ # SPDX-License-Identifier: CC0-1.0 conf_files = files([ + 'ov08x40.yaml', 'uncalibrated.yaml', ]) diff --git a/src/ipa/simple/data/ov08x40.yaml b/src/ipa/simple/data/ov08x40.yaml new file mode 100644 index 0000000..aa1b8e0 --- /dev/null +++ b/src/ipa/simple/data/ov08x40.yaml @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: CC0-1.0 +%YAML 1.1 +--- +version: 1 +algorithms: + - BlackLevel: + - Awb: + - Ccm: + ccms: + - ct: 3050 + ccm: [ 1.12, -0.08, -0.04, + -0.05, 1.00, 0.05, + -0.02, -0.10, 1.12 ] + offsets: [ 0, 0, 0 ] + - Adjust: + contrast: 1.15 + gamma: 2.2 + - Agc: + target: 2.3 + maxAnalogueGain: 3.0 + maxExposureTimeMs: 33.0 +...