From patchwork Thu May 9 17:55:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 20033 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 A7601C32B5 for ; Thu, 9 May 2024 17:56:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 61B8C63467; Thu, 9 May 2024 19:56:15 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Nf7zK6I6"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7EF9A633FA for ; Thu, 9 May 2024 19:56:12 +0200 (CEST) Received: from neptunite.hamster-moth.ts.net (h175-177-049-156.catv02.itscom.jp [175.177.49.156]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AA3C0CC8; Thu, 9 May 2024 19:56:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1715277368; bh=GUHN6GfS2ArfjHzi/iNBAQWD3y2NfZIjf7y9B652ZSE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Nf7zK6I6Nf6gLIPLtHxbvt813UohFF0pWsvLVv4lUBNGBkR9aM8194EpuBYptdkM4 hyNk5inqMV2O9EUjXWts7cWH6paiDMdfCyJVQR48IH5F6HByhRGERailh5yU4oiDx2 JyQK33zeQcgdDtkAR0r/QhbzVVCbfyqxoI8V7Rhg= From: Paul Elder To: libcamera-devel@lists.libcamera.org Cc: Paul Elder , Stefan Klug Subject: [PATCH v2 2/3] ipa: libipa: agc: Change luminance target to piecewise linear function Date: Fri, 10 May 2024 02:55:54 +0900 Message-Id: <20240509175555.43121-3-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240509175555.43121-1-paul.elder@ideasonboard.com> References: <20240509175555.43121-1-paul.elder@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" Change the relative luminance target from a scalar value to a piecewise linear function that needs to be sampled by the estimate lux value. Also change the rkisp1 and ipu3 IPAs accordingly, as they use the libipa agc. As they both don't yet have lux modules, hardcode them to a single lux value for now. This affects the format of the tuning files, but as there aren't yet any this shouldn't be an issue. Signed-off-by: Paul Elder Reviewed-by: Stefan Klug --- Changes in v2: - s/FPoint/PointF/ - add warning when using default relative luminance target when loading from the tuning file fails --- src/ipa/ipu3/algorithms/agc.cpp | 5 ++++- src/ipa/libipa/agc_mean_luminance.cpp | 31 +++++++++++++++++++++------ src/ipa/libipa/agc_mean_luminance.h | 7 +++--- src/ipa/rkisp1/algorithms/agc.cpp | 5 ++++- 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp index c9b5548c..984ed087 100644 --- a/src/ipa/ipu3/algorithms/agc.cpp +++ b/src/ipa/ipu3/algorithms/agc.cpp @@ -222,12 +222,15 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, double analogueGain = frameContext.sensor.gain; utils::Duration effectiveExposureValue = exposureTime * analogueGain; + /* \todo Plumb in the lux value. Requires a lux algo + tuning */ + double lux = 400; + utils::Duration shutterTime; double aGain, dGain; std::tie(shutterTime, aGain, dGain) = calculateNewEv(context.activeState.agc.constraintMode, context.activeState.agc.exposureMode, hist, - effectiveExposureValue); + effectiveExposureValue, lux); LOG(IPU3Agc, Debug) << "Divided up shutter, analogue gain and digital gain are " diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp index 2bf84d05..fe07777d 100644 --- a/src/ipa/libipa/agc_mean_luminance.cpp +++ b/src/ipa/libipa/agc_mean_luminance.cpp @@ -134,7 +134,7 @@ static constexpr double kDefaultRelativeLuminanceTarget = 0.16; */ AgcMeanLuminance::AgcMeanLuminance() - : frameCount_(0), filteredExposure_(0s), relativeLuminanceTarget_(0) + : frameCount_(0), filteredExposure_(0s) { } @@ -142,8 +142,16 @@ AgcMeanLuminance::~AgcMeanLuminance() = default; void AgcMeanLuminance::parseRelativeLuminanceTarget(const YamlObject &tuningData) { - relativeLuminanceTarget_ = - tuningData["relativeLuminanceTarget"].get(kDefaultRelativeLuminanceTarget); + int ret = relativeLuminanceTarget_.readYaml(tuningData["relativeLuminanceTarget"]); + if (ret == 0) + return; + + LOG(AgcMeanLuminance, Warning) + << "Failed to load tuning parameter 'relativeLuminanceTarget', " + << "using default [0, " << kDefaultRelativeLuminanceTarget << "]"; + + std::vector points = { { 0, kDefaultRelativeLuminanceTarget } }; + relativeLuminanceTarget_ = Pwl(points); } void AgcMeanLuminance::parseConstraint(const YamlObject &modeDict, int32_t id) @@ -421,11 +429,18 @@ void AgcMeanLuminance::setLimits(utils::Duration minShutter, /** * \brief Estimate the initial gain needed to achieve a relative luminance * target + * \param[in] lux The lux value at which to sample the luminance target pwl + * + * To account for non-linearity caused by saturation, the value needs to be + * estimated in an iterative process, as multiplying by a gain will not increase + * the relative luminance by the same factor if some image regions are saturated + * * \return The calculated initial gain */ -double AgcMeanLuminance::estimateInitialGain() const +double AgcMeanLuminance::estimateInitialGain(double lux) const { - double yTarget = relativeLuminanceTarget_; + double yTarget = + relativeLuminanceTarget_.eval(relativeLuminanceTarget_.domain().clamp(lux)); double yGain = 1.0; /* @@ -520,6 +535,7 @@ utils::Duration AgcMeanLuminance::filterExposure(utils::Duration exposureValue) * the calculated gain * \param[in] effectiveExposureValue The EV applied to the frame from which the * statistics in use derive + * \param[in] lux The lux value at which to sample the luminance target pwl * * Calculate a new exposure value to try to obtain the target. The calculated * exposure value is filtered to prevent rapid changes from frame to frame, and @@ -531,7 +547,8 @@ std::tuple AgcMeanLuminance::calculateNewEv(uint32_t constraintModeIndex, uint32_t exposureModeIndex, const Histogram &yHist, - utils::Duration effectiveExposureValue) + utils::Duration effectiveExposureValue, + double lux) { /* * The pipeline handler should validate that we have received an allowed @@ -540,7 +557,7 @@ AgcMeanLuminance::calculateNewEv(uint32_t constraintModeIndex, std::shared_ptr exposureModeHelper = exposureModeHelpers_.at(exposureModeIndex); - double gain = estimateInitialGain(); + double gain = estimateInitialGain(lux); gain = constraintClampGain(constraintModeIndex, yHist, gain); /* diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h index 0a81c6d2..6ec2a0dc 100644 --- a/src/ipa/libipa/agc_mean_luminance.h +++ b/src/ipa/libipa/agc_mean_luminance.h @@ -18,6 +18,7 @@ #include "exposure_mode_helper.h" #include "histogram.h" +#include "pwl.h" namespace libcamera { @@ -62,7 +63,7 @@ public: std::tuple calculateNewEv(uint32_t constraintModeIndex, uint32_t exposureModeIndex, - const Histogram &yHist, utils::Duration effectiveExposureValue); + const Histogram &yHist, utils::Duration effectiveExposureValue, double lux); void resetFrameCount() { @@ -76,7 +77,7 @@ private: void parseConstraint(const YamlObject &modeDict, int32_t id); int parseConstraintModes(const YamlObject &tuningData); int parseExposureModes(const YamlObject &tuningData); - double estimateInitialGain() const; + double estimateInitialGain(double lux) const; double constraintClampGain(uint32_t constraintModeIndex, const Histogram &hist, double gain); @@ -84,7 +85,7 @@ private: uint64_t frameCount_; utils::Duration filteredExposure_; - double relativeLuminanceTarget_; + Pwl relativeLuminanceTarget_; std::map> constraintModes_; std::map> exposureModeHelpers_; diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index 4fc06277..bd9a6a66 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -384,12 +384,15 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, double analogueGain = frameContext.sensor.gain; utils::Duration effectiveExposureValue = exposureTime * analogueGain; + /* \todo Plumb in the lux value. Requires a lux algo + tuning */ + double lux = 400; + utils::Duration shutterTime; double aGain, dGain; std::tie(shutterTime, aGain, dGain) = calculateNewEv(context.activeState.agc.constraintMode, context.activeState.agc.exposureMode, - hist, effectiveExposureValue); + hist, effectiveExposureValue, lux); LOG(RkISP1Agc, Debug) << "Divided up shutter, analogue gain and digital gain are "