Show a patch.

GET /api/1.1/patches/15000/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 15000,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/15000/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/15000/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20211202180410.518232-7-jeanmichel.hautbois@ideasonboard.com>",
    "date": "2021-12-02T18:04:10",
    "name": "[libcamera-devel,v1,6/6] ipa: rkisp1: agc: Introduce histogram calculation",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "e0073ed1aac63895236d6ee3484dfbedb483d34c",
    "submitter": {
        "id": 75,
        "url": "https://patchwork.libcamera.org/api/1.1/people/75/?format=api",
        "name": "Jean-Michel Hautbois",
        "email": "jeanmichel.hautbois@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/15000/mbox/",
    "series": [
        {
            "id": 2805,
            "url": "https://patchwork.libcamera.org/api/1.1/series/2805/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=2805",
            "date": "2021-12-02T18:04:04",
            "name": "IPA RkISP1 awb and misc improvements",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/2805/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/15000/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/15000/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 27A84C3253\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  2 Dec 2021 18:04:23 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 943FC60882;\n\tThu,  2 Dec 2021 19:04:22 +0100 (CET)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9D3BF60862\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  2 Dec 2021 19:04:16 +0100 (CET)",
            "from tatooine.ideasonboard.com (unknown\n\t[IPv6:2a01:e0a:169:7140:7fc3:78ca:aeee:c4f2])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 63411464;\n\tThu,  2 Dec 2021 19:04:16 +0100 (CET)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"gsAPi8zq\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1638468256;\n\tbh=ppsOUgkmYauVFkGBK/l6allqw/wsIYMvja+t0VOfpvM=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=gsAPi8zqKqFvAnBUb6DXWfBWx+oH3eM3VcZY4B2r8Xw6HSsSNMOerxo9HM7SXvw4o\n\tqweM6WMZeQfs81RhmwG8G4BugpiLjS5U9FGFlSO1Nt9tOLFFWp9RUldYkagGriAz6N\n\tdlpLoxHsLPQY0YiVVmx67ix/aU/WOVNC6VRTWhas=",
        "From": "Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>",
        "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",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v1 6/6] ipa: rkisp1: agc: Introduce\n\thistogram calculation",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "As for the IPU3, we can estimate the histogram of the luminance. The\nRkISP1 can estimate multiple ones, the R, G and B ones, the Y only one\nand a combination of RGB. The one we are interested by in AGC is the Y\nhistogram.\n\nUse the hardware revision to determine the number of bins of the\nproduced histogram, and use it to populate a vector passed down to the\nlibipa::Histogram class.\n\nAs the sensor deGamma and AWB are applied, we also need to get back to\nthe relative luminance value of 0.16, as for the IPU3.\n\nSigned-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>\n---\n src/ipa/rkisp1/algorithms/agc.cpp | 87 ++++++++++++++++++++++++++-----\n src/ipa/rkisp1/algorithms/agc.h   |  4 +-\n 2 files changed, 77 insertions(+), 14 deletions(-)",
    "diff": "diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\nindex f95ecfde5..dd7b26ae7 100644\n--- a/src/ipa/rkisp1/algorithms/agc.cpp\n+++ b/src/ipa/rkisp1/algorithms/agc.cpp\n@@ -15,6 +15,8 @@\n \n #include <libcamera/ipa/core_ipa_interface.h>\n \n+#include \"libipa/histogram.h\"\n+\n /**\n  * \\file agc.h\n  */\n@@ -42,6 +44,9 @@ static constexpr utils::Duration kMaxShutterSpeed = 60ms;\n /* Number of frames to wait before calculating stats on minimum exposure */\n static constexpr uint32_t kNumStartupFrames = 10;\n \n+/* Target value to reach for the top 2% of the histogram */\n+static constexpr double kEvGainTarget = 0.5;\n+\n /*\n  * Relative luminance target.\n  *\n@@ -50,10 +55,10 @@ static constexpr uint32_t kNumStartupFrames = 10;\n  *\n  * \\todo Why is the value different between IPU3 and RkISP1 ?\n  */\n-static constexpr double kRelativeLuminanceTarget = 0.4;\n+static constexpr double kRelativeLuminanceTarget = 0.16;\n \n Agc::Agc()\n-\t: frameCount_(0), numCells_(0), filteredExposure_(0s)\n+\t: frameCount_(0), numCells_(0), numHistBins_(0), filteredExposure_(0s)\n {\n }\n \n@@ -64,8 +69,7 @@ Agc::Agc()\n  *\n  * \\return 0\n  */\n-int Agc::configure(IPAContext &context,\n-\t\t   [[maybe_unused]] const IPACameraSensorInfo &configInfo)\n+int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)\n {\n \t/* Configure the default exposure and gain. */\n \tcontext.frameContext.agc.gain = std::max(context.configuration.agc.minAnalogueGain, kMinAnalogueGain);\n@@ -76,10 +80,19 @@ int Agc::configure(IPAContext &context,\n \t * - versions < V12 have RKISP1_CIF_ISP_AE_MEAN_MAX_V10 entries,\n \t * - versions >= V12 have RKISP1_CIF_ISP_AE_MEAN_MAX_V12 entries.\n \t */\n-\tif (context.configuration.hw.revision < RKISP1_V12)\n+\tif (context.configuration.hw.revision < RKISP1_V12) {\n \t\tnumCells_ = RKISP1_CIF_ISP_AE_MEAN_MAX_V10;\n-\telse\n+\t\tnumHistBins_ = RKISP1_CIF_ISP_HIST_BIN_N_MAX_V10;\n+\t} else {\n \t\tnumCells_ = RKISP1_CIF_ISP_AE_MEAN_MAX_V12;\n+\t\tnumHistBins_ = RKISP1_CIF_ISP_HIST_BIN_N_MAX_V12;\n+\t}\n+\n+\t/* Define the measurement window for AGC. */\n+\tcontext.configuration.agc.measureWindow.h_offs = configInfo.outputSize.width / 8;\n+\tcontext.configuration.agc.measureWindow.v_offs = configInfo.outputSize.height / 8;\n+\tcontext.configuration.agc.measureWindow.h_size = 3 * configInfo.outputSize.width / 4;\n+\tcontext.configuration.agc.measureWindow.v_size = 3 * configInfo.outputSize.height / 4;\n \n \treturn 0;\n }\n@@ -124,7 +137,7 @@ utils::Duration Agc::filterExposure(utils::Duration exposureValue)\n  * \\param[inout] frameContext The shared IPA frame Context\n  * \\param[in] yGain The gain calculated on the current brightness level\n  */\n-void Agc::computeExposure(IPAContext &context, double yGain)\n+void Agc::computeExposure(IPAContext &context, double yGain, double iqMeanGain)\n {\n \tIPASessionConfiguration &configuration = context.configuration;\n \tIPAFrameContext &frameContext = context.frameContext;\n@@ -133,6 +146,9 @@ void Agc::computeExposure(IPAContext &context, double yGain)\n \tuint32_t exposure = frameContext.sensor.exposure;\n \tdouble analogueGain = frameContext.sensor.gain;\n \n+\t/* Use the highest of the two gain estimates. */\n+\tdouble evGain = std::max(yGain, iqMeanGain);\n+\n \tutils::Duration minShutterSpeed = configuration.agc.minShutterSpeed;\n \tutils::Duration maxShutterSpeed = std::min(configuration.agc.maxShutterSpeed,\n \t\t\t\t\t\t   kMaxShutterSpeed);\n@@ -143,7 +159,7 @@ void Agc::computeExposure(IPAContext &context, double yGain)\n \t\t\t\t\t  kMaxAnalogueGain);\n \n \t/* Consider within 1% of the target as correctly exposed. */\n-\tif (std::abs(yGain - 1.0) < 0.01)\n+\tif (std::abs(evGain - 1.0) < 0.01)\n \t\treturn;\n \n \t/* extracted from Rpi::Agc::computeTargetExposure. */\n@@ -160,13 +176,13 @@ void Agc::computeExposure(IPAContext &context, double yGain)\n \tLOG(RkISP1Agc, Debug) << \"Actual total exposure \" << currentShutter * analogueGain\n \t\t\t      << \" Shutter speed \" << currentShutter\n \t\t\t      << \" Gain \" << analogueGain\n-\t\t\t      << \" Needed ev gain \" << yGain;\n+\t\t\t      << \" Needed ev gain \" << evGain;\n \n \t/*\n \t * Calculate the current exposure value for the scene as the latest\n \t * exposure value applied multiplied by the new estimated gain.\n \t */\n-\tutils::Duration exposureValue = effectiveExposureValue * yGain;\n+\tutils::Duration exposureValue = effectiveExposureValue * evGain;\n \n \t/* Clamp the exposure value to the min and max authorized. */\n \tutils::Duration maxTotalExposure = maxShutterSpeed * maxAnalogueGain;\n@@ -237,6 +253,23 @@ double Agc::estimateLuminance(const rkisp1_cif_isp_ae_stat *ae,\n \treturn ySum / numCells_ / 255;\n }\n \n+/**\n+ * \\brief Estimate the mean value of the top 2% of the histogram\n+ * \\param[in] hist The histogram statistics computed by the ImgU\n+ * \\return The mean value of the top 2% of the histogram\n+ */\n+double Agc::measureBrightness(const rkisp1_cif_isp_hist_stat *hist) const\n+{\n+\tstd::vector<uint32_t> measHist(numHistBins_);\n+\n+\t/* Initialise the histogram array using the maximum available size */\n+\tfor (unsigned int histBin = 0; histBin < numHistBins_; histBin++)\n+\t\tmeasHist.push_back(hist->hist_bins[histBin]);\n+\n+\t/* Estimate the quantile mean of the top 2% of the histogram. */\n+\treturn Histogram(Span<uint32_t>(measHist)).interQuantileMean(0.98, 1.0);\n+}\n+\n /**\n  * \\brief Process RkISP1 statistics, and run AGC operations\n  * \\param[in] context The shared IPA context\n@@ -251,9 +284,13 @@ void Agc::process(IPAContext &context, const rkisp1_stat_buffer *stats)\n \tASSERT(stats->meas_type & RKISP1_CIF_ISP_STAT_AUTOEXP);\n \n \tconst rkisp1_cif_isp_ae_stat *ae = &params->ae;\n+\tconst rkisp1_cif_isp_hist_stat *hist = &params->hist;\n \n \tframeCount_ = context.frameContext.frameId;\n \n+\tdouble iqMean = measureBrightness(hist);\n+\tdouble iqMeanGain = kEvGainTarget * numHistBins_ / iqMean;\n+\n \t/*\n \t * Estimate the gain needed to achieve a relative luminance target. To\n \t * account for non-linearity caused by saturation, the value needs to be\n@@ -276,14 +313,38 @@ void Agc::process(IPAContext &context, const rkisp1_stat_buffer *stats)\n \t\t\tbreak;\n \t}\n \n-\tcomputeExposure(context, yGain);\n+\tcomputeExposure(context, yGain, iqMeanGain);\n }\n \n-void Agc::prepare([[maybe_unused]] IPAContext &context,\n-\t\t  rkisp1_params_cfg *params)\n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::prepare\n+ */\n+void Agc::prepare(IPAContext &context, rkisp1_params_cfg *params)\n {\n+\t/* Configure the measurement window. */\n+\tparams->meas.aec_config.meas_window = context.configuration.agc.measureWindow;\n+\t/* Use a continuous methode for measure. */\n+\tparams->meas.aec_config.autostop = RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0;\n+\t/* Estimate Y as (R + G + B) x (85/256). */\n+\tparams->meas.aec_config.mode = RKISP1_CIF_ISP_EXP_MEASURING_MODE_1;\n+\tparams->module_cfg_update |= RKISP1_CIF_ISP_MODULE_AEC;\n \tparams->module_ens |= RKISP1_CIF_ISP_MODULE_AEC;\n \tparams->module_en_update |= RKISP1_CIF_ISP_MODULE_AEC;\n+\n+\t/* Configure histogram. */\n+\tparams->meas.hst_config.meas_window = context.configuration.agc.measureWindow;\n+\t/* Produce the luminance histogram. */\n+\tparams->meas.hst_config.mode = RKISP1_CIF_ISP_HISTOGRAM_MODE_Y_HISTOGRAM;\n+\t/* Set an average weighted histogram. */\n+\tfor (unsigned int histBin = 0; histBin < numHistBins_; histBin++)\n+\t\tparams->meas.hst_config.hist_weight[histBin] = 1;\n+\t/* Step size can't be less than 3. */\n+\tparams->meas.hst_config.histogram_predivider = 4;\n+\t/* Update the configuration for histogram. */\n+\tparams->module_cfg_update |= RKISP1_CIF_ISP_MODULE_HST;\n+\t/* Enable the histogram measure unit. */\n+\tparams->module_ens |= RKISP1_CIF_ISP_MODULE_HST;\n+\tparams->module_en_update |= RKISP1_CIF_ISP_MODULE_HST;\n }\n \n } /* namespace ipa::rkisp1::algorithms */\ndiff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h\nindex 942c9d7a6..872776d0e 100644\n--- a/src/ipa/rkisp1/algorithms/agc.h\n+++ b/src/ipa/rkisp1/algorithms/agc.h\n@@ -32,13 +32,15 @@ public:\n \tvoid process(IPAContext &context, const rkisp1_stat_buffer *stats) override;\n \n private:\n-\tvoid computeExposure(IPAContext &Context, double yGain);\n+\tvoid computeExposure(IPAContext &Context, double yGain, double iqMeanGain);\n \tutils::Duration filterExposure(utils::Duration exposureValue);\n \tdouble estimateLuminance(const rkisp1_cif_isp_ae_stat *ae, double gain);\n+\tdouble measureBrightness(const rkisp1_cif_isp_hist_stat *hist) const;\n \n \tuint64_t frameCount_;\n \n \tuint32_t numCells_;\n+\tuint32_t numHistBins_;\n \n \tutils::Duration filteredExposure_;\n };\n",
    "prefixes": [
        "libcamera-devel",
        "v1",
        "6/6"
    ]
}