From patchwork Thu Feb 27 10:57:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keke Li X-Patchwork-Id: 22889 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 69ED1BF415 for ; Thu, 27 Feb 2025 10:58:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 277FB6875D; Thu, 27 Feb 2025 11:58:56 +0100 (CET) Received: from mail-sh.amlogic.com (unknown [58.32.228.46]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F394A68749 for ; Thu, 27 Feb 2025 11:58:54 +0100 (CET) Received: from droid10.amlogic.com (10.18.11.213) by mail-sh.amlogic.com (10.18.11.5) with Microsoft SMTP Server id 15.1.2507.39; Thu, 27 Feb 2025 18:58:53 +0800 From: Keke Li To: CC: , , , Keke Li Subject: [PATCH v3 06/11] ipa: c3-isp: Add Awb algorithm Date: Thu, 27 Feb 2025 18:57:28 +0800 Message-ID: <20250227105733.187611-7-keke.li@amlogic.com> X-Mailer: git-send-email 2.29.0 In-Reply-To: <20250227105733.187611-1-keke.li@amlogic.com> References: <20250227105733.187611-1-keke.li@amlogic.com> MIME-Version: 1.0 X-Originating-IP: [10.18.11.213] 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 a new Awb algorithm for the C3 ISP. Signed-off-by: Keke Li --- src/ipa/c3-isp/algorithms/awb.cpp | 200 ++++++++++++++++++++++++++ src/ipa/c3-isp/algorithms/awb.h | 39 +++++ src/ipa/c3-isp/algorithms/meson.build | 1 + 3 files changed, 240 insertions(+) create mode 100644 src/ipa/c3-isp/algorithms/awb.cpp create mode 100644 src/ipa/c3-isp/algorithms/awb.h diff --git a/src/ipa/c3-isp/algorithms/awb.cpp b/src/ipa/c3-isp/algorithms/awb.cpp new file mode 100644 index 00000000..786dcc81 --- /dev/null +++ b/src/ipa/c3-isp/algorithms/awb.cpp @@ -0,0 +1,200 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Amlogic + * + * C3ISP AWB control algorithm + */ + +#include "awb.h" + +#include + +#include +#include + +#include + +#include "libipa/colours.h" +#include "libipa/fixedpoint.h" + +/** + * \file awb.h + */ + +namespace libcamera { + +namespace ipa::c3isp::algorithms { + +/** + * \class Awb + * \brief A Grey world white balance correction algorithm + */ + +LOG_DEFINE_CATEGORY(C3ISPAwb) + +Awb::Awb() +{ +} + +/** + * \copydoc libcamera::ipa::Algorithm::configure + */ +int Awb::configure(IPAContext &context, + [[maybe_unused]] const IPACameraSensorInfo &configInfo) +{ + context.activeState.awb.rGain = 1.0; + context.activeState.awb.bGain = 1.0; + + return 0; +} + +void Awb::fillGainsParam(IPAContext &context, IPAFrameContext &frameContext, + C3ISPParams *params) +{ + double rGain = context.activeState.awb.rGain; + double bGain = context.activeState.awb.bGain; + + auto AWBGains = params->block(); + AWBGains.setEnabled(C3_ISP_PARAMS_BLOCK_FL_ENABLE); + + AWBGains->gr_gain = floatingToFixedPoint<4, 8, uint16_t, double>(1.0); + AWBGains->r_gain = floatingToFixedPoint<4, 8, uint16_t, double>(rGain); + AWBGains->b_gain = floatingToFixedPoint<4, 8, uint16_t, double>(bGain); + AWBGains->gb_gain = floatingToFixedPoint<4, 8, uint16_t, double>(1.0); + + frameContext.awb.rGain = rGain; + frameContext.awb.bGain = bGain; +} + +void Awb::fillConfigParam(IPAContext &context, C3ISPParams *params) +{ + auto AWBCfg = params->block(); + AWBCfg.setEnabled(C3_ISP_PARAMS_BLOCK_FL_ENABLE); + + AWBCfg->tap_point = C3_ISP_AWB_STATS_TAP_BEFORE_WB; + AWBCfg->satur_vald = 1; + + /* We use the full 32x24 zoning scheme */ + AWBCfg->horiz_zones_num = 32; + AWBCfg->vert_zones_num = 24; + + /* The ratios themselves are stored in Q4.8 format */ + AWBCfg->rg_min = 75; + AWBCfg->rg_max = 256; + AWBCfg->bg_min = 44; + AWBCfg->bg_max = 222; + + /* The triming of ratios are stored in Q4.8 format */ + AWBCfg->rg_low = 93; + AWBCfg->rg_high = 244; + AWBCfg->bg_low = 61; + AWBCfg->bg_high = 205; + + Span weights{ AWBCfg->zone_weight, C3_ISP_AWB_MAX_ZONES }; + std::fill(weights.begin(), weights.end(), 1); + + Size sensorSize = context.configuration.sensor.size; + uint8_t maxPointNum = + std::max(AWBCfg->horiz_zones_num, AWBCfg->vert_zones_num) + 1; + + for (unsigned int i = 0; i < maxPointNum; i++) { + uint16_t hidx = i * sensorSize.width / AWBCfg->horiz_zones_num; + + /* Aligned with 2 */ + hidx = hidx / 2 * 2; + AWBCfg->horiz_coord[i] = std::min(hidx, (uint16_t)sensorSize.width); + + uint16_t vidx = i * sensorSize.height / AWBCfg->vert_zones_num; + + /* Aligned with 2 */ + vidx = vidx / 2 * 2; + AWBCfg->vert_coord[i] = std::min(vidx, (uint16_t)sensorSize.height); + } +} + +/** + * \copydoc libcamera::ipa::Algorithm::prepare + */ +void Awb::prepare(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, C3ISPParams *params) +{ + fillGainsParam(context, frameContext, params); + + if (frame > 0) + return; + + fillConfigParam(context, params); +} + +/** + * \copydoc libcamera::ipa::Algorithm::process + */ +void Awb::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, const c3_isp_stats_info *stats, + ControlList &metadata) +{ + IPAActiveState &activeState = context.activeState; + const struct c3_isp_awb_stats *awb = &stats->awb; + + /* The AWB statistics are R:G and B:G ratios of the zones. */ + uint32_t counted_zones = 0; + double rgSum = 0, bgSum = 0; + + for (unsigned int i = 0; i < C3_ISP_AWB_MAX_ZONES; i++) { + if (!awb->stats[i].pixel_sum) + continue; + + /* The statistics are in Q4.12 format. */ + rgSum += fixedToFloatingPoint<4, 12, double, uint16_t>(awb->stats[i].rg); + bgSum += fixedToFloatingPoint<4, 12, double, uint16_t>(awb->stats[i].bg); + + counted_zones++; + } + + double rgAvg, bgAvg; + if (!counted_zones) { + rgAvg = 1.0; + bgAvg = 1.0; + } else { + rgAvg = rgSum / counted_zones; + bgAvg = bgSum / counted_zones; + } + + /* + * To simplify the calculation, the average green is hardcoded + * to 1.0. + */ + activeState.awb.temperatureK = estimateCCT({ { rgAvg, 1.0, bgAvg } }); + + /* Metadata shall contain the up to date measurement */ + metadata.set(controls::ColourTemperature, activeState.awb.temperatureK); + + /* + * Estimate the red and blue gains to apply in a grey world. + * The green gain is hardcoded to 1.0. Avoid division by zero + * by clamping the divisor to mininum value of 0.0625. + */ + double rGain = 1 / std::max(rgAvg, 0.0625); + double bGain = 1 / std::max(bgAvg, 0.0625); + + /* Filter the values to avoid oscillations. */ + double speed = 0.2; + rGain = speed * rGain + (1 - speed) * activeState.awb.rGain; + bGain = speed * bGain + (1 - speed) * activeState.awb.bGain; + + activeState.awb.rGain = rGain; + activeState.awb.bGain = bGain; + + metadata.set(controls::ColourGains, { static_cast(frameContext.awb.rGain), + static_cast(frameContext.awb.bGain) }); + + LOG(C3ISPAwb, Debug) << "Gains: R " << activeState.awb.rGain + << ", B " << activeState.awb.bGain + << ", Ct " << activeState.awb.temperatureK << "K"; +} + +REGISTER_IPA_ALGORITHM(Awb, "Awb") + +} /* namespace ipa::c3isp::algorithms */ + +} /* namespace libcamera */ diff --git a/src/ipa/c3-isp/algorithms/awb.h b/src/ipa/c3-isp/algorithms/awb.h new file mode 100644 index 00000000..bd036c11 --- /dev/null +++ b/src/ipa/c3-isp/algorithms/awb.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Amlogic + * + * C3ISP AWB control algorithm + */ + +#pragma once + +#include "algorithm.h" + +namespace libcamera { + +namespace ipa::c3isp::algorithms { + +class Awb : public Algorithm +{ +public: + Awb(); + ~Awb() = default; + + int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; + void prepare(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + C3ISPParams *params) override; + void process(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + const c3_isp_stats_info *stats, + ControlList &metadata) override; + +private: + void fillGainsParam(IPAContext &context, IPAFrameContext &frameContext, + C3ISPParams *params); + void fillConfigParam(IPAContext &context, C3ISPParams *params); +}; + +} /* namespace ipa::c3isp::algorithms */ + +} /* namespace libcamera */ diff --git a/src/ipa/c3-isp/algorithms/meson.build b/src/ipa/c3-isp/algorithms/meson.build index 3e44fe91..9460da99 100644 --- a/src/ipa/c3-isp/algorithms/meson.build +++ b/src/ipa/c3-isp/algorithms/meson.build @@ -2,4 +2,5 @@ c3isp_ipa_algorithms = files([ 'agc.cpp', + 'awb.cpp', ])