From patchwork Sun Feb 8 17:44:48 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 26105 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 08D57BD78E for ; Sun, 8 Feb 2026 17:45:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8B551620B8; Sun, 8 Feb 2026 18:45:48 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="SpaxgjD0"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8B85D620A3 for ; Sun, 8 Feb 2026 18:45:44 +0100 (CET) Received: from rui-Precision-7560.tail5b760b.ts.net (unknown [209.216.103.65]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B4CB6E72; Sun, 8 Feb 2026 18:44:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1770572699; bh=9Lz7WXkX5zZBIll/anol1T/awTSdG+P6YmmQZ1GcNVo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SpaxgjD0enaK/sAnisRqvsIlgdwwUR9fCxQxd7e/3b42CjK8Pbksb9Z+DPpleQc7c X2+jZnbQnMAeaqRt3fjCrPl27iYrLbz5fFiiOKApAq/oJKJBTO/OFGBSR8yw3lF6QY NXi7igsDtQtIlhcUY+C7Go5eX9jdnjmhtcKxWmlA= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 2/4] ipa: rkisp1: dpf: Implement manual noise reduction mode Date: Sun, 8 Feb 2026 12:44:48 -0500 Message-ID: <20260208174450.416314-3-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260208174450.416314-1-rui.wang@ideasonboard.com> References: <20260208174450.416314-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" Support manual control of the Denoise Pre-Filter (DPF) parameters. - When the manual noise reduction mode is selected, apply the control values to the DPF configuration and enable the hardware block if requested. - DPF register values can be applied manually from controls. Register the DPF vendor controls with appropriate limits and defaults. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/dpf.cpp | 116 +++++++++++++++++++++++++++++- src/ipa/rkisp1/algorithms/dpf.h | 1 + 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index df6bef87..c232f2ad 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -135,6 +135,49 @@ void Dpf::registerControls(IPAContext &context) */ context.ctrlMap[&controls::draft::NoiseReductionMode] = ControlInfo(modes, activeMode_->modeValue); + if (noiseReductionModes_.empty()) + return; + /* if active mode is setted, set active mode config to control map + else set first mode config to control map + */ + const ModeConfig *config = nullptr; + if (activeMode_->modeValue != controls::draft::NoiseReductionModeOff) + config = &(*activeMode_); + else + config = &noiseReductionModes_[0]; + /* Set the default enable value to the active mode */ + context.ctrlMap[&controls::rkisp1::DpfEnable] = ControlInfo(0, 1, config->modeValue == controls::draft::NoiseReductionModeOff ? 0 : 1); + + std::array strengthDefault = { + static_cast(config->strength.r), + static_cast(config->strength.g), + static_cast(config->strength.b) + }; + context.ctrlMap[&controls::rkisp1::DpfChannelStrengths] = + ControlInfo(1, 255, Span(strengthDefault)); + + std::array greenCoeffs; + std::copy(std::begin(config->dpf.g_flt.spatial_coeff), std::end(config->dpf.g_flt.spatial_coeff), greenCoeffs.begin()); + context.ctrlMap[&controls::rkisp1::DpfGreenSpatialCoefficients] = + ControlInfo(0, 16, Span(greenCoeffs)); + + context.ctrlMap[&controls::rkisp1::DpfRedBlueFilterSize] = + ControlInfo(controls::rkisp1::DpfRedBlueFilterSizeValues, + ControlValue(static_cast(config->dpf.rb_flt.fltsize))); + + std::array redBlueCoeffs; + std::copy(std::begin(config->dpf.rb_flt.spatial_coeff), std::end(config->dpf.rb_flt.spatial_coeff), redBlueCoeffs.begin()); + context.ctrlMap[&controls::rkisp1::DpfRedBlueSpatialCoefficients] = + ControlInfo(0, 16, Span(redBlueCoeffs)); + + std::array nllCoeffs; + std::copy(std::begin(config->dpf.nll.coeff), std::end(config->dpf.nll.coeff), nllCoeffs.begin()); + context.ctrlMap[&controls::rkisp1::DpfNoiseLevelLookupCoefficients] = + ControlInfo(1, 1023, Span(nllCoeffs)); + + context.ctrlMap[&controls::rkisp1::DpfNoiseLevelLookupScaleMode] = + ControlInfo(controls::rkisp1::DpfNoiseLevelLookupScaleModeValues, + ControlValue(static_cast(config->dpf.nll.scale_mode))); } int Dpf::parseSingleConfig(const YamlObject &tuningData, @@ -339,7 +382,8 @@ void Dpf::queueRequest(IPAContext &context, bool update = false; const auto &denoise = controls.get(controls::draft::NoiseReductionMode); - if (denoise) { + /* only update denoise mode when it has changed */ + if (denoise && activeMode_->modeValue != *denoise) { switch (*denoise) { case controls::draft::NoiseReductionModeOff: if (dpf.denoise) { @@ -351,6 +395,7 @@ void Dpf::queueRequest(IPAContext &context, case controls::draft::NoiseReductionModeHighQuality: case controls::draft::NoiseReductionModeFast: case controls::draft::NoiseReductionModeZSL: + case controls::draft::NoiseReductionModeManual: if (loadConfig(*denoise)) { update = true; dpf.denoise = true; @@ -365,6 +410,24 @@ void Dpf::queueRequest(IPAContext &context, if (update) LOG(RkISP1Dpf, Debug) << "Set denoise to " << *denoise; } + /* handle manual mode, collect all dpf config from controls */ + if (activeMode_->modeValue == controls::draft::NoiseReductionModeManual) { + /* + * In manual mode, if DpfEnable is present and true, we enable DPF. + * If DpfEnable is present and false, we disable DPF. + * If DpfEnable is not present, we keep the previous state (or default). + */ + const auto &enable = controls.get(controls::rkisp1::DpfEnable); + if (*enable) { + dpf.denoise = true; + update = true; + } + bool ret = parseControls(controls); + if (!ret) { + LOG(RkISP1Dpf, Error) << "Failed to collect manual overrides"; + return; + } + } frameContext.dpf.denoise = dpf.denoise; frameContext.dpf.update = update; @@ -437,6 +500,57 @@ void Dpf::prepareEnabledMode(IPAContext &context, IPAFrameContext &frameContext, logConfig(frameContext, *config, *strengthConfig); } +bool Dpf::parseControls(const ControlList &controls) +{ + /* + * activeMode_ is a const_iterator, so we need to find the mutable element + * in noiseReductionModes_, and parse the controls values into manualMode + * config + */ + const auto it = std::find_if(noiseReductionModes_.begin(), noiseReductionModes_.end(), + [](const ModeConfig &mode) { + return mode.modeValue == controls::draft::NoiseReductionModeManual; + }); + + if (it == noiseReductionModes_.end()) { + LOG(RkISP1Dpf, Error) << "Manual mode not found in configuration"; + return false; + } + + ModeConfig &config = *it; + + if (const auto &c = controls.get(controls::rkisp1::DpfGreenSpatialCoefficients); c) + if (c->size() == RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS) + std::copy(c->begin(), c->end(), std::begin(config.dpf.g_flt.spatial_coeff)); + + config.dpf.rb_flt.r_enable = true; + config.dpf.rb_flt.b_enable = true; + + if (const auto &c = controls.get(controls::rkisp1::DpfRedBlueSpatialCoefficients); c) { + if (c->size() == RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS || c->size() == RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - 1) + std::copy(c->begin(), c->end(), std::begin(config.dpf.rb_flt.spatial_coeff)); + } + + if (const auto &c = controls.get(controls::rkisp1::DpfRedBlueFilterSize); c) + config.dpf.rb_flt.fltsize = *c; + + if (const auto &c = controls.get(controls::rkisp1::DpfNoiseLevelLookupCoefficients); c) + if (c->size() == RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS) + std::copy(c->begin(), c->end(), std::begin(config.dpf.nll.coeff)); + + if (const auto &c = controls.get(controls::rkisp1::DpfNoiseLevelLookupScaleMode); c) + config.dpf.nll.scale_mode = *c; + + if (const auto &c = controls.get(controls::rkisp1::DpfChannelStrengths); c) + if (c->size() == 3) { + config.strength.r = (*c)[0]; + config.strength.g = (*c)[1]; + config.strength.b = (*c)[2]; + } + + return true; +} + REGISTER_IPA_ALGORITHM(Dpf, "Dpf") } /* namespace ipa::rkisp1::algorithms */ diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 66d3f302..e3dea97b 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -41,6 +41,7 @@ private: int parseSingleConfig(const YamlObject &tuningData, rkisp1_cif_isp_dpf_config &config, rkisp1_cif_isp_dpf_strength_config &strengthConfig); + bool parseControls(const ControlList &controls); bool loadConfig(int32_t mode); void logConfig(const IPAFrameContext &frameContext,