From patchwork Fri Nov 13 16:40:49 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 28904 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 7534DC335E for ; Fri, 13 Nov 2026 16:41:28 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AF6FF6A82A; Fri, 13 Nov 2026 17:41:25 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="MN2lwONh"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8ACDA6A833 for ; Fri, 13 Nov 2026 17:41:08 +0100 (CET) Received: from pb-laptop.local (185.221.140.49.nat.pool.zt.hu [185.221.140.49]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C2F63269; Fri, 13 Nov 2026 17:38:43 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1794587923; bh=cNnf/sQ4MZIRRj4g2Ku0q1oAqOYDfuLArBAyT9VjRo4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MN2lwONhL0TW6BW3zIeMmn5qUdGbt1BWdUmdaQyg1TxxTO7yNx4g7EG1U1I6KGcTr 9cmfYaQepiqpa6Sg3O9BcFVhgZrnO1/WcVPFHUGICL6AyDBKccRQUVwRFzShV1c6m5 G5vkyzUQUY0Bj66C/Ewn69DPE8kgzegEbGxPuVrs= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi Subject: [PATCH v4 16/21] ipa: rppx1: lux: Add Date: Fri, 13 Nov 2026 17:40:49 +0100 Message-ID: <20261113164054.267164-17-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.56.1 In-Reply-To: <20261113164054.267164-1-barnabas.pocze@ideasonboard.com> References: <20261113164054.267164-1-barnabas.pocze@ideasonboard.com> MIME-Version: 1.0 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: Jacopo Mondi Add the algorithm to the rppx1 ipa module based on the corresponding algorithm in the rkisp1 ipa module. Signed-off-by: Jacopo Mondi Signed-off-by: Barnabás Pőcze --- src/ipa/rppx1/algorithms/agc.cpp | 1 + src/ipa/rppx1/algorithms/awb.cpp | 2 +- src/ipa/rppx1/algorithms/lux.cpp | 76 ++++++++++++++++++++++++++++ src/ipa/rppx1/algorithms/lux.h | 36 +++++++++++++ src/ipa/rppx1/algorithms/meson.build | 1 + src/ipa/rppx1/ipa_context.h | 8 +++ 6 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 src/ipa/rppx1/algorithms/lux.cpp create mode 100644 src/ipa/rppx1/algorithms/lux.h diff --git a/src/ipa/rppx1/algorithms/agc.cpp b/src/ipa/rppx1/algorithms/agc.cpp index eff1f4d065..0853e29760 100644 --- a/src/ipa/rppx1/algorithms/agc.cpp +++ b/src/ipa/rppx1/algorithms/agc.cpp @@ -333,6 +333,7 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, }, .exposure = frameContext.sensor.exposure, .gain = frameContext.sensor.gain, + .lux = frameContext.lux.lux, }}, metadata); } else { agc_.process(context.configuration.agc, context.activeState.agc, frameContext.agc, {}, metadata); diff --git a/src/ipa/rppx1/algorithms/awb.cpp b/src/ipa/rppx1/algorithms/awb.cpp index 5e23b88146..fe7d64d77d 100644 --- a/src/ipa/rppx1/algorithms/awb.cpp +++ b/src/ipa/rppx1/algorithms/awb.cpp @@ -209,7 +209,7 @@ void Awb::process(IPAContext &context, RppX1AwbStats awbStats = calculateRgbMeans(frameContext, *awb); awbAlgo_.process(context.activeState.awb, frameContext.awb, awbStats, - 0, metadata); + frameContext.lux.lux, metadata); } RppX1AwbStats Awb::calculateRgbMeans(const IPAFrameContext &frameContext, diff --git a/src/ipa/rppx1/algorithms/lux.cpp b/src/ipa/rppx1/algorithms/lux.cpp new file mode 100644 index 0000000000..41ae8e1ab6 --- /dev/null +++ b/src/ipa/rppx1/algorithms/lux.cpp @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026, Ideas On Board + * + * RPP-X1 Lux estimation + */ + +#include "lux.h" + +#include + +#include + +#include "libipa/histogram.h" +#include "libipa/lux.h" + +/** + * \file lux.h + */ + +namespace libcamera { + +namespace ipa::rppx1::algorithms { + +/** + * \copydoc libcamera::ipa::Algorithm::init + */ +int Lux::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) +{ + return lux_.parseTuningData(tuningData); +} + +/** + * \copydoc libcamera::ipa::Algorithm::prepare + */ +void Lux::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, + [[maybe_unused]] RppX1Params *params) +{ + frameContext.lux.lux = context.activeState.lux.lux; +} + +/** + * \copydoc libcamera::ipa::Algorithm::process + */ +void Lux::process(IPAContext &context, + [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, + const RppX1Stats *stats, + ControlList &metadata) +{ + /* + * Report the lux level used by algorithms to prepare this frame + * not the lux level *of* this frame. + */ + metadata.set(controls::Lux, frameContext.lux.lux); + + utils::Duration exposureTime = context.configuration.agc.lineDuration * + frameContext.sensor.exposure; + double gain = frameContext.sensor.gain; + + /* \todo Deduplicate the histogram calculation from AGC */ + const auto histPost = stats->block(); + if (!histPost) + return; + + Histogram yHist(histPost->hist_bins, [](uint32_t x) { return x >> 4; }); + + context.activeState.lux.lux = lux_.estimateLux(exposureTime, gain, 1.0, yHist); +} + +REGISTER_IPA_ALGORITHM(Lux, "Lux") + +} /* namespace ipa::rppx1::algorithms */ + +} /* namespace libcamera */ diff --git a/src/ipa/rppx1/algorithms/lux.h b/src/ipa/rppx1/algorithms/lux.h new file mode 100644 index 0000000000..e38835be2b --- /dev/null +++ b/src/ipa/rppx1/algorithms/lux.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026, Ideas On Board + * + * RPP-X1 Lux estimation + */ + +#pragma once + +#include "libipa/lux.h" + +#include "algorithm.h" + +namespace libcamera { + +namespace ipa::rppx1::algorithms { + +class Lux : public Algorithm +{ +public: + int init(IPAContext &context, const ValueNode &tuningData) override; + void prepare(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + RppX1Params *params) override; + void process(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + const RppX1Stats *stats, + ControlList &metadata) override; + +private: + ipa::Lux lux_; +}; + +} /* namespace ipa::rppx1::algorithms */ + +} /* namespace libcamera */ diff --git a/src/ipa/rppx1/algorithms/meson.build b/src/ipa/rppx1/algorithms/meson.build index 4a2c1b52dd..19688854a3 100644 --- a/src/ipa/rppx1/algorithms/meson.build +++ b/src/ipa/rppx1/algorithms/meson.build @@ -4,4 +4,5 @@ rppx1_ipa_algorithms = files([ 'agc.cpp', 'awb.cpp', 'blc.cpp', + 'lux.cpp', ]) diff --git a/src/ipa/rppx1/ipa_context.h b/src/ipa/rppx1/ipa_context.h index 24fbbfaa28..9dfc67f252 100644 --- a/src/ipa/rppx1/ipa_context.h +++ b/src/ipa/rppx1/ipa_context.h @@ -42,6 +42,10 @@ struct IPAActiveState { } agc; ipa::awb::ActiveState awb; + + struct { + double lux; + } lux; }; struct IPAFrameContext : public FrameContext { @@ -56,6 +60,10 @@ struct IPAFrameContext : public FrameContext { } agc; ipa::awb::FrameContext awb; + + struct { + double lux; + } lux; }; struct IPAContext {