From patchwork Sun Jan 18 20:29:50 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 25826 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 0C92BBDCBE for ; Sun, 18 Jan 2026 20:30:43 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C8B0161FB9; Sun, 18 Jan 2026 21:30:42 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="skJ70AEK"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EEC3661FB9 for ; Sun, 18 Jan 2026 21:30:40 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.103.65]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BFEB51BA; Sun, 18 Jan 2026 21:30:10 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768768211; bh=fY8F3AL+hPMykr4ZGbXKshuzs571yQFx8yt80SPlZeg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=skJ70AEKQKmaOQs/1BMCgHadLA6QScRe0dHzPixOAaAaPQIR5aM9HCvE1lVPncpWk Un/UYWqDxq39i6IBcBL6+rAdZrp91tBv+mt02t9csCXW1QkVg3noXeo6wTPISeawoS 6mIYRfh4gN1EPPzWfDzHtAXxC1JXI4/ln5GW+aw8= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 1/4] ipa: rkisp1: algorithms: filter: Implement noise reduction mode switching Date: Sun, 18 Jan 2026 15:29:50 -0500 Message-ID: <20260118202953.1554892-2-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260118202953.1554892-1-rui.wang@ideasonboard.com> References: <20260118202953.1554892-1-rui.wang@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" Add support for switching between different noise reduction modes in the Filter algorithm, mirroring the implementation approach used in the DPF algorithm. This allows the Filter to be configured with multiple mode-specific parameter sets, enabling runtime switching between different filtering strengths via the NoiseReductionMode control. Key changes: - Introduce ModeConfig structure to store mode-specific filter configurations. - Implement parseConfig() to parse NoiseReductionModes from tuning data. - Add parseSingleConfig() to parse individual mode configurations with inheritance support (modes can override base config values). - Implement loadConfig() to switch between configured modes at runtime. - Add kModesMap for string-to-int mode name mapping. - Support optional ActiveMode tuning parameter to set default mode. - Add modeName() helper for reverse lookup (int to string) for logging. The implementation follows the same pattern as the DPF algorithm, ensuring consistency across the rkisp1 IPA module. Example YAML configuration for Filter: - Filter: NoiseReductionModes: - type: "ReductionMinimal" mode: 1266 # 0x000004f2 in decimal lum_weight: 139328 # 0x00022040 in decimal grn_stage1: 6 chr_h_mode: 3 chr_v_mode: 3 thresh_bl0: 8 thresh_bl1: 2 thresh_sh0: 18 thresh_sh1: 33 fac_sh0: 4 fac_sh1: 4 fac_mid: 4 fac_bl0: 2 fac_bl1: 0 - type: "fast" ... ActiveMode: "ReductionMinimal" Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/filter.cpp | 149 ++++++++++++++++++++++++++- src/ipa/rkisp1/algorithms/filter.h | 16 ++- 2 files changed, 163 insertions(+), 2 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/filter.cpp b/src/ipa/rkisp1/algorithms/filter.cpp index 8ad79801..321e4122 100644 --- a/src/ipa/rkisp1/algorithms/filter.cpp +++ b/src/ipa/rkisp1/algorithms/filter.cpp @@ -8,11 +8,17 @@ #include "filter.h" #include +#include +#include +#include +#include #include #include +#include "linux/rkisp1-config.h" + /** * \file filter.h */ @@ -36,20 +42,161 @@ namespace ipa::rkisp1::algorithms { LOG_DEFINE_CATEGORY(RkISP1Filter) +namespace { + static constexpr uint32_t kFiltLumWeightDefault = 0x00022040; static constexpr uint32_t kFiltModeDefault = 0x000004f2; +const std::map kModesMap = { + { "ReductionMinimal", controls::draft::NoiseReductionModeMinimal }, + { "ReductionFast", controls::draft::NoiseReductionModeFast }, + { "ReductionHighQuality", controls::draft::NoiseReductionModeHighQuality }, + { "ReductionZSL", controls::draft::NoiseReductionModeZSL }, + { "ReductionOff", controls::draft::NoiseReductionModeOff }, +}; + +std::string modeName(int32_t mode) +{ + auto it = std::find_if(kModesMap.begin(), kModesMap.end(), + [mode](const auto &pair) { + return pair.second == mode; + }); + + if (it != kModesMap.end()) + return it->first; + + return "ReductionUnknown"; +} +} /* namespace */ + +Filter::Filter() + : noiseReductionModes_({}), + activeMode_(noiseReductionModes_.end()) +{ +} + /** * \copydoc libcamera::ipa::Algorithm::init */ int Filter::init(IPAContext &context, - [[maybe_unused]] const YamlObject &tuningData) + const YamlObject &tuningData) { auto &cmap = context.ctrlMap; cmap[&controls::Sharpness] = ControlInfo(0.0f, 10.0f, 1.0f); + /* Parse tuning block. */ + int ret = parseConfig(tuningData); + if (ret) + return ret; + + return 0; +} + +int Filter::parseConfig(const YamlObject &tuningData) +{ + /* Parse noise reduction modes. */ + if (!tuningData.contains("NoiseReductionModes")) { + LOG(RkISP1Filter, Error) << "Missing modes in Filter tuning data"; + return -EINVAL; + } + + noiseReductionModes_.clear(); + for (const auto &entry : tuningData["NoiseReductionModes"].asList()) { + std::optional typeOpt = + entry["type"].get(); + if (!typeOpt) { + LOG(RkISP1Filter, Error) << "Modes entry missing type"; + return -EINVAL; + } + + ModeConfig mode; + auto it = kModesMap.find(*typeOpt); + if (it == kModesMap.end()) { + LOG(RkISP1Filter, Error) << "Unknown mode type: " << *typeOpt; + return -EINVAL; + } + + mode.modeValue = it->second; + int ret = parseSingleConfig(entry, mode.config); + if (ret) { + LOG(RkISP1Filter, Error) << "Failed to parse mode: " << *typeOpt; + return ret; + } + + noiseReductionModes_.push_back(mode); + } + + /* + * Parse the optional ActiveMode. + * If not present, default to "ReductionOff". + */ + std::string activeMode = tuningData["ActiveMode"].get().value_or("ReductionOff"); + auto it = kModesMap.find(activeMode); + if (it == kModesMap.end()) { + LOG(RkISP1Filter, Warning) << "Invalid ActiveMode: " << activeMode; + activeMode_ = noiseReductionModes_.end(); + return 0; + } + + if (!loadConfig(it->second)) { + /* If the default "ReductionOff" mode is requested but not configured, disable Filter. */ + if (it->second == controls::draft::NoiseReductionModeOff) + activeMode_ = noiseReductionModes_.end(); + else + return -EINVAL; + } + + return 0; +} +int Filter::parseSingleConfig(const YamlObject &tuningData, + struct rkisp1_cif_isp_flt_config &config) +{ + if (!tuningData.contains("mode") || !tuningData.contains("lum_weight")) { + LOG(RkISP1Filter, Error) << "Modes entry missing mode or lum_weight"; + return -EINVAL; + } + + config.mode = tuningData["mode"].get().value_or(kFiltModeDefault); + config.lum_weight = tuningData["lum_weight"].get().value_or(kFiltLumWeightDefault); + config.grn_stage1 = tuningData["grn_stage1"].get().value_or(config.grn_stage1); + config.chr_h_mode = tuningData["chr_h_mode"].get().value_or(config.chr_h_mode); + config.chr_v_mode = tuningData["chr_v_mode"].get().value_or(config.chr_v_mode); + + config.thresh_bl0 = tuningData["thresh_bl0"].get().value_or(config.thresh_bl0); + config.thresh_bl1 = tuningData["thresh_bl1"].get().value_or(config.thresh_bl1); + config.thresh_sh0 = tuningData["thresh_sh0"].get().value_or(config.thresh_sh0); + config.thresh_sh1 = tuningData["thresh_sh1"].get().value_or(config.thresh_sh1); + + config.fac_sh0 = tuningData["fac_sh0"].get().value_or(config.fac_sh0); + config.fac_sh1 = tuningData["fac_sh1"].get().value_or(config.fac_sh1); + config.fac_mid = tuningData["fac_mid"].get().value_or(config.fac_mid); + config.fac_bl0 = tuningData["fac_bl0"].get().value_or(config.fac_bl0); + config.fac_bl1 = tuningData["fac_bl1"].get().value_or(config.fac_bl1); + return 0; } + +bool Filter::loadConfig(int32_t mode) +{ + auto it = std::find_if(noiseReductionModes_.begin(), noiseReductionModes_.end(), + [mode](const ModeConfig &m) { + return m.modeValue == mode; + }); + if (it == noiseReductionModes_.end()) { + LOG(RkISP1Filter, Warning) + << "No Filter config for reduction mode: " << modeName(mode); + return false; + } + + activeMode_ = it; + + LOG(RkISP1Filter, Debug) + << "Filter mode=Reduction (config loaded)" + << " mode= " << modeName(mode); + + return true; +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ diff --git a/src/ipa/rkisp1/algorithms/filter.h b/src/ipa/rkisp1/algorithms/filter.h index 37d8938d..3860adfd 100644 --- a/src/ipa/rkisp1/algorithms/filter.h +++ b/src/ipa/rkisp1/algorithms/filter.h @@ -18,7 +18,7 @@ namespace ipa::rkisp1::algorithms { class Filter : public Algorithm { public: - Filter() = default; + Filter(); ~Filter() = default; int init(IPAContext &context, const YamlObject &tuningData) override; @@ -28,6 +28,20 @@ public: void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) override; + +private: + struct ModeConfig { + int32_t modeValue; + rkisp1_cif_isp_flt_config config; + }; + + int parseConfig(const YamlObject &tuningData); + int parseSingleConfig(const YamlObject &tuningData, + struct rkisp1_cif_isp_flt_config &config); + + bool loadConfig(int32_t mode); + std::vector noiseReductionModes_; + std::vector::const_iterator activeMode_; }; } /* namespace ipa::rkisp1::algorithms */