From patchwork Thu Dec 2 18:04:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Michel Hautbois X-Patchwork-Id: 15000 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 27A84C3253 for ; Thu, 2 Dec 2021 18:04:23 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 943FC60882; Thu, 2 Dec 2021 19:04:22 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="gsAPi8zq"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9D3BF60862 for ; Thu, 2 Dec 2021 19:04:16 +0100 (CET) Received: from tatooine.ideasonboard.com (unknown [IPv6:2a01:e0a:169:7140:7fc3:78ca:aeee:c4f2]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 63411464; Thu, 2 Dec 2021 19:04:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1638468256; bh=ppsOUgkmYauVFkGBK/l6allqw/wsIYMvja+t0VOfpvM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gsAPi8zqKqFvAnBUb6DXWfBWx+oH3eM3VcZY4B2r8Xw6HSsSNMOerxo9HM7SXvw4o qweM6WMZeQfs81RhmwG8G4BugpiLjS5U9FGFlSO1Nt9tOLFFWp9RUldYkagGriAz6N dlpLoxHsLPQY0YiVVmx67ix/aU/WOVNC6VRTWhas= From: Jean-Michel Hautbois To: libcamera-devel@lists.libcamera.org Date: Thu, 2 Dec 2021 19:04:10 +0100 Message-Id: <20211202180410.518232-7-jeanmichel.hautbois@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211202180410.518232-1-jeanmichel.hautbois@ideasonboard.com> References: <20211202180410.518232-1-jeanmichel.hautbois@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v1 6/6] ipa: rkisp1: agc: Introduce histogram calculation 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" As for the IPU3, we can estimate the histogram of the luminance. The RkISP1 can estimate multiple ones, the R, G and B ones, the Y only one and a combination of RGB. The one we are interested by in AGC is the Y histogram. Use the hardware revision to determine the number of bins of the produced histogram, and use it to populate a vector passed down to the libipa::Histogram class. As the sensor deGamma and AWB are applied, we also need to get back to the relative luminance value of 0.16, as for the IPU3. Signed-off-by: Jean-Michel Hautbois --- src/ipa/rkisp1/algorithms/agc.cpp | 87 ++++++++++++++++++++++++++----- src/ipa/rkisp1/algorithms/agc.h | 4 +- 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index f95ecfde5..dd7b26ae7 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -15,6 +15,8 @@ #include +#include "libipa/histogram.h" + /** * \file agc.h */ @@ -42,6 +44,9 @@ static constexpr utils::Duration kMaxShutterSpeed = 60ms; /* Number of frames to wait before calculating stats on minimum exposure */ static constexpr uint32_t kNumStartupFrames = 10; +/* Target value to reach for the top 2% of the histogram */ +static constexpr double kEvGainTarget = 0.5; + /* * Relative luminance target. * @@ -50,10 +55,10 @@ static constexpr uint32_t kNumStartupFrames = 10; * * \todo Why is the value different between IPU3 and RkISP1 ? */ -static constexpr double kRelativeLuminanceTarget = 0.4; +static constexpr double kRelativeLuminanceTarget = 0.16; Agc::Agc() - : frameCount_(0), numCells_(0), filteredExposure_(0s) + : frameCount_(0), numCells_(0), numHistBins_(0), filteredExposure_(0s) { } @@ -64,8 +69,7 @@ Agc::Agc() * * \return 0 */ -int Agc::configure(IPAContext &context, - [[maybe_unused]] const IPACameraSensorInfo &configInfo) +int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo) { /* Configure the default exposure and gain. */ context.frameContext.agc.gain = std::max(context.configuration.agc.minAnalogueGain, kMinAnalogueGain); @@ -76,10 +80,19 @@ int Agc::configure(IPAContext &context, * - versions < V12 have RKISP1_CIF_ISP_AE_MEAN_MAX_V10 entries, * - versions >= V12 have RKISP1_CIF_ISP_AE_MEAN_MAX_V12 entries. */ - if (context.configuration.hw.revision < RKISP1_V12) + if (context.configuration.hw.revision < RKISP1_V12) { numCells_ = RKISP1_CIF_ISP_AE_MEAN_MAX_V10; - else + numHistBins_ = RKISP1_CIF_ISP_HIST_BIN_N_MAX_V10; + } else { numCells_ = RKISP1_CIF_ISP_AE_MEAN_MAX_V12; + numHistBins_ = RKISP1_CIF_ISP_HIST_BIN_N_MAX_V12; + } + + /* Define the measurement window for AGC. */ + context.configuration.agc.measureWindow.h_offs = configInfo.outputSize.width / 8; + context.configuration.agc.measureWindow.v_offs = configInfo.outputSize.height / 8; + context.configuration.agc.measureWindow.h_size = 3 * configInfo.outputSize.width / 4; + context.configuration.agc.measureWindow.v_size = 3 * configInfo.outputSize.height / 4; return 0; } @@ -124,7 +137,7 @@ utils::Duration Agc::filterExposure(utils::Duration exposureValue) * \param[inout] frameContext The shared IPA frame Context * \param[in] yGain The gain calculated on the current brightness level */ -void Agc::computeExposure(IPAContext &context, double yGain) +void Agc::computeExposure(IPAContext &context, double yGain, double iqMeanGain) { IPASessionConfiguration &configuration = context.configuration; IPAFrameContext &frameContext = context.frameContext; @@ -133,6 +146,9 @@ void Agc::computeExposure(IPAContext &context, double yGain) uint32_t exposure = frameContext.sensor.exposure; double analogueGain = frameContext.sensor.gain; + /* Use the highest of the two gain estimates. */ + double evGain = std::max(yGain, iqMeanGain); + utils::Duration minShutterSpeed = configuration.agc.minShutterSpeed; utils::Duration maxShutterSpeed = std::min(configuration.agc.maxShutterSpeed, kMaxShutterSpeed); @@ -143,7 +159,7 @@ void Agc::computeExposure(IPAContext &context, double yGain) kMaxAnalogueGain); /* Consider within 1% of the target as correctly exposed. */ - if (std::abs(yGain - 1.0) < 0.01) + if (std::abs(evGain - 1.0) < 0.01) return; /* extracted from Rpi::Agc::computeTargetExposure. */ @@ -160,13 +176,13 @@ void Agc::computeExposure(IPAContext &context, double yGain) LOG(RkISP1Agc, Debug) << "Actual total exposure " << currentShutter * analogueGain << " Shutter speed " << currentShutter << " Gain " << analogueGain - << " Needed ev gain " << yGain; + << " Needed ev gain " << evGain; /* * Calculate the current exposure value for the scene as the latest * exposure value applied multiplied by the new estimated gain. */ - utils::Duration exposureValue = effectiveExposureValue * yGain; + utils::Duration exposureValue = effectiveExposureValue * evGain; /* Clamp the exposure value to the min and max authorized. */ utils::Duration maxTotalExposure = maxShutterSpeed * maxAnalogueGain; @@ -237,6 +253,23 @@ double Agc::estimateLuminance(const rkisp1_cif_isp_ae_stat *ae, return ySum / numCells_ / 255; } +/** + * \brief Estimate the mean value of the top 2% of the histogram + * \param[in] hist The histogram statistics computed by the ImgU + * \return The mean value of the top 2% of the histogram + */ +double Agc::measureBrightness(const rkisp1_cif_isp_hist_stat *hist) const +{ + std::vector measHist(numHistBins_); + + /* Initialise the histogram array using the maximum available size */ + for (unsigned int histBin = 0; histBin < numHistBins_; histBin++) + measHist.push_back(hist->hist_bins[histBin]); + + /* Estimate the quantile mean of the top 2% of the histogram. */ + return Histogram(Span(measHist)).interQuantileMean(0.98, 1.0); +} + /** * \brief Process RkISP1 statistics, and run AGC operations * \param[in] context The shared IPA context @@ -251,9 +284,13 @@ void Agc::process(IPAContext &context, const rkisp1_stat_buffer *stats) ASSERT(stats->meas_type & RKISP1_CIF_ISP_STAT_AUTOEXP); const rkisp1_cif_isp_ae_stat *ae = ¶ms->ae; + const rkisp1_cif_isp_hist_stat *hist = ¶ms->hist; frameCount_ = context.frameContext.frameId; + double iqMean = measureBrightness(hist); + double iqMeanGain = kEvGainTarget * numHistBins_ / iqMean; + /* * Estimate the gain needed to achieve a relative luminance target. To * account for non-linearity caused by saturation, the value needs to be @@ -276,14 +313,38 @@ void Agc::process(IPAContext &context, const rkisp1_stat_buffer *stats) break; } - computeExposure(context, yGain); + computeExposure(context, yGain, iqMeanGain); } -void Agc::prepare([[maybe_unused]] IPAContext &context, - rkisp1_params_cfg *params) +/** + * \copydoc libcamera::ipa::Algorithm::prepare + */ +void Agc::prepare(IPAContext &context, rkisp1_params_cfg *params) { + /* Configure the measurement window. */ + params->meas.aec_config.meas_window = context.configuration.agc.measureWindow; + /* Use a continuous methode for measure. */ + params->meas.aec_config.autostop = RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0; + /* Estimate Y as (R + G + B) x (85/256). */ + params->meas.aec_config.mode = RKISP1_CIF_ISP_EXP_MEASURING_MODE_1; + params->module_cfg_update |= RKISP1_CIF_ISP_MODULE_AEC; params->module_ens |= RKISP1_CIF_ISP_MODULE_AEC; params->module_en_update |= RKISP1_CIF_ISP_MODULE_AEC; + + /* Configure histogram. */ + params->meas.hst_config.meas_window = context.configuration.agc.measureWindow; + /* Produce the luminance histogram. */ + params->meas.hst_config.mode = RKISP1_CIF_ISP_HISTOGRAM_MODE_Y_HISTOGRAM; + /* Set an average weighted histogram. */ + for (unsigned int histBin = 0; histBin < numHistBins_; histBin++) + params->meas.hst_config.hist_weight[histBin] = 1; + /* Step size can't be less than 3. */ + params->meas.hst_config.histogram_predivider = 4; + /* Update the configuration for histogram. */ + params->module_cfg_update |= RKISP1_CIF_ISP_MODULE_HST; + /* Enable the histogram measure unit. */ + params->module_ens |= RKISP1_CIF_ISP_MODULE_HST; + params->module_en_update |= RKISP1_CIF_ISP_MODULE_HST; } } /* namespace ipa::rkisp1::algorithms */ diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h index 942c9d7a6..872776d0e 100644 --- a/src/ipa/rkisp1/algorithms/agc.h +++ b/src/ipa/rkisp1/algorithms/agc.h @@ -32,13 +32,15 @@ public: void process(IPAContext &context, const rkisp1_stat_buffer *stats) override; private: - void computeExposure(IPAContext &Context, double yGain); + void computeExposure(IPAContext &Context, double yGain, double iqMeanGain); utils::Duration filterExposure(utils::Duration exposureValue); double estimateLuminance(const rkisp1_cif_isp_ae_stat *ae, double gain); + double measureBrightness(const rkisp1_cif_isp_hist_stat *hist) const; uint64_t frameCount_; uint32_t numCells_; + uint32_t numHistBins_; utils::Duration filteredExposure_; };