Show a patch.

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

{
    "id": 20231,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/20231/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/20231/",
    "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": "<20240607080330.2667994-3-paul.elder@ideasonboard.com>",
    "date": "2024-06-07T08:03:29",
    "name": "[v5,2/3] ipa: libipa: agc: Change luminance target to piecewise linear function",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "4a22b15e8e649394fb845bae096857356066a39d",
    "submitter": {
        "id": 17,
        "url": "https://patchwork.libcamera.org/api/1.1/people/17/?format=api",
        "name": "Paul Elder",
        "email": "paul.elder@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/20231/mbox/",
    "series": [
        {
            "id": 4372,
            "url": "https://patchwork.libcamera.org/api/1.1/series/4372/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4372",
            "date": "2024-06-07T08:03:27",
            "name": "ipa: rkisp1: Improve AGC (plumbing)",
            "version": 5,
            "mbox": "https://patchwork.libcamera.org/series/4372/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/20231/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/20231/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 A7A4CC3292\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  7 Jun 2024 08:03:56 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 85BC665468;\n\tFri,  7 Jun 2024 10:03:55 +0200 (CEST)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0D5F765457\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  7 Jun 2024 10:03:53 +0200 (CEST)",
            "from neptunite.hamster-moth.ts.net\n\t(h175-177-049-156.catv02.itscom.jp [175.177.49.156])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 1A190EA2;\n\tFri,  7 Jun 2024 10:03:41 +0200 (CEST)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"I32p5bQ1\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1717747423;\n\tbh=JHLec/yRsLevXuueqO9GyUaGkEczk2EvsTZaW6moL9Y=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=I32p5bQ12LZkqG+/ApnFH6gdA3+a0jj8ZR776ikmK2XtzmXgya/kSGBPx7F2U5nLQ\n\ti+p3YEzKgwVNyDgHiZ/Zl48C4MDPq661sgGoqKM+tOM1mm6SeYlax62B7ryi9wqrq9\n\t7cOeBpLjm/eIYKrGcPvOxl5uYGqLjv8GC7ftK95k=",
        "From": "Paul Elder <paul.elder@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Paul Elder <paul.elder@ideasonboard.com>,\n\tStefan Klug <stefan.klug@ideasonboard.com>,\n\tDaniel Scally <dan.scally@ideasonboard.com>",
        "Subject": "[PATCH v5 2/3] ipa: libipa: agc: Change luminance target to\n\tpiecewise linear function",
        "Date": "Fri,  7 Jun 2024 17:03:29 +0900",
        "Message-Id": "<20240607080330.2667994-3-paul.elder@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.39.2",
        "In-Reply-To": "<20240607080330.2667994-1-paul.elder@ideasonboard.com>",
        "References": "<20240607080330.2667994-1-paul.elder@ideasonboard.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "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": "Change the relative luminance target from a scalar value to a piecewise\nlinear function that needs to be sampled by the estimate lux value.\n\nAlso change the rkisp1 and ipu3 IPAs accordingly, as they use the libipa\nagc. As they both don't yet have lux modules, hardcode them to a single\nlux value for now.\n\nThis affects the format of the tuning files, but as there aren't yet any\nthis shouldn't be an issue.\n\nSigned-off-by: Paul Elder <paul.elder@ideasonboard.com>\nReviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>\nReviewed-by: Daniel Scally <dan.scally@ideasonboard.com>\n\n---\nChanges in v5:\n- use new PointF that's a typedef of Vector\n\nChanges in v4:\n- construct default pwl with *two* points so that it succeeds\n\nNo change in v3\n\nChanges in v2:\n- s/FPoint/PointF/\n- add warning when using default relative luminance target when loading\n  from the tuning file fails\n---\n src/ipa/ipu3/algorithms/agc.cpp       |  5 ++++-\n src/ipa/libipa/agc_mean_luminance.cpp | 32 +++++++++++++++++++++------\n src/ipa/libipa/agc_mean_luminance.h   |  7 +++---\n src/ipa/rkisp1/algorithms/agc.cpp     |  5 ++++-\n 4 files changed, 37 insertions(+), 12 deletions(-)",
    "diff": "diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\nindex 0e0114f6d..7f71bec06 100644\n--- a/src/ipa/ipu3/algorithms/agc.cpp\n+++ b/src/ipa/ipu3/algorithms/agc.cpp\n@@ -222,12 +222,15 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n \tdouble analogueGain = frameContext.sensor.gain;\n \tutils::Duration effectiveExposureValue = exposureTime * analogueGain;\n \n+\t/* \\todo Plumb in the lux value. Requires a lux algo + tuning */\n+\tdouble lux = 400;\n+\n \tutils::Duration shutterTime;\n \tdouble aGain, dGain;\n \tstd::tie(shutterTime, aGain, dGain) =\n \t\tcalculateNewEv(context.activeState.agc.constraintMode,\n \t\t\t       context.activeState.agc.exposureMode, hist,\n-\t\t\t       effectiveExposureValue);\n+\t\t\t       effectiveExposureValue, lux);\n \n \tLOG(IPU3Agc, Debug)\n \t\t<< \"Divided up shutter, analogue gain and digital gain are \"\ndiff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp\nindex 271b5ae4b..10c16850d 100644\n--- a/src/ipa/libipa/agc_mean_luminance.cpp\n+++ b/src/ipa/libipa/agc_mean_luminance.cpp\n@@ -134,7 +134,7 @@ static constexpr double kDefaultRelativeLuminanceTarget = 0.16;\n  */\n \n AgcMeanLuminance::AgcMeanLuminance()\n-\t: frameCount_(0), filteredExposure_(0s), relativeLuminanceTarget_(0)\n+\t: frameCount_(0), filteredExposure_(0s)\n {\n }\n \n@@ -142,8 +142,17 @@ AgcMeanLuminance::~AgcMeanLuminance() = default;\n \n void AgcMeanLuminance::parseRelativeLuminanceTarget(const YamlObject &tuningData)\n {\n-\trelativeLuminanceTarget_ =\n-\t\ttuningData[\"relativeLuminanceTarget\"].get<double>(kDefaultRelativeLuminanceTarget);\n+\tint ret = relativeLuminanceTarget_.readYaml(tuningData[\"relativeLuminanceTarget\"]);\n+\tif (ret == 0)\n+\t\treturn;\n+\n+\tLOG(AgcMeanLuminance, Warning)\n+\t\t<< \"Failed to load tuning parameter 'relativeLuminanceTarget', \"\n+\t\t<< \"using default [0, \" << kDefaultRelativeLuminanceTarget << \"]\";\n+\n+\tstd::vector<Pwl::PointF> points = { Pwl::PointF({     0, kDefaultRelativeLuminanceTarget }),\n+\t\t\t\t\t    Pwl::PointF({ 10000, kDefaultRelativeLuminanceTarget }) };\n+\trelativeLuminanceTarget_ = Pwl(points);\n }\n \n void AgcMeanLuminance::parseConstraint(const YamlObject &modeDict, int32_t id)\n@@ -421,11 +430,18 @@ void AgcMeanLuminance::setLimits(utils::Duration minShutter,\n /**\n  * \\brief Estimate the initial gain needed to achieve a relative luminance\n  * target\n+ * \\param[in] lux The lux value at which to sample the luminance target pwl\n+ *\n+ * To account for non-linearity caused by saturation, the value needs to be\n+ * estimated in an iterative process, as multiplying by a gain will not increase\n+ * the relative luminance by the same factor if some image regions are saturated\n+ *\n  * \\return The calculated initial gain\n  */\n-double AgcMeanLuminance::estimateInitialGain() const\n+double AgcMeanLuminance::estimateInitialGain(double lux) const\n {\n-\tdouble yTarget = relativeLuminanceTarget_;\n+\tdouble yTarget =\n+\t\trelativeLuminanceTarget_.eval(relativeLuminanceTarget_.domain().clamp(lux));\n \tdouble yGain = 1.0;\n \n \t/*\n@@ -520,6 +536,7 @@ utils::Duration AgcMeanLuminance::filterExposure(utils::Duration exposureValue)\n  * the calculated gain\n  * \\param[in] effectiveExposureValue The EV applied to the frame from which the\n  * statistics in use derive\n+ * \\param[in] lux The lux value at which to sample the luminance target pwl\n  *\n  * Calculate a new exposure value to try to obtain the target. The calculated\n  * exposure value is filtered to prevent rapid changes from frame to frame, and\n@@ -531,7 +548,8 @@ std::tuple<utils::Duration, double, double>\n AgcMeanLuminance::calculateNewEv(uint32_t constraintModeIndex,\n \t\t\t\t uint32_t exposureModeIndex,\n \t\t\t\t const Histogram &yHist,\n-\t\t\t\t utils::Duration effectiveExposureValue)\n+\t\t\t\t utils::Duration effectiveExposureValue,\n+\t\t\t\t double lux)\n {\n \t/*\n \t * The pipeline handler should validate that we have received an allowed\n@@ -540,7 +558,7 @@ AgcMeanLuminance::calculateNewEv(uint32_t constraintModeIndex,\n \tstd::shared_ptr<ExposureModeHelper> exposureModeHelper =\n \t\texposureModeHelpers_.at(exposureModeIndex);\n \n-\tdouble gain = estimateInitialGain();\n+\tdouble gain = estimateInitialGain(lux);\n \tgain = constraintClampGain(constraintModeIndex, yHist, gain);\n \n \t/*\ndiff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h\nindex 0a81c6d28..6ec2a0dc9 100644\n--- a/src/ipa/libipa/agc_mean_luminance.h\n+++ b/src/ipa/libipa/agc_mean_luminance.h\n@@ -18,6 +18,7 @@\n \n #include \"exposure_mode_helper.h\"\n #include \"histogram.h\"\n+#include \"pwl.h\"\n \n namespace libcamera {\n \n@@ -62,7 +63,7 @@ public:\n \n \tstd::tuple<utils::Duration, double, double>\n \tcalculateNewEv(uint32_t constraintModeIndex, uint32_t exposureModeIndex,\n-\t\t       const Histogram &yHist, utils::Duration effectiveExposureValue);\n+\t\t       const Histogram &yHist, utils::Duration effectiveExposureValue, double lux);\n \n \tvoid resetFrameCount()\n \t{\n@@ -76,7 +77,7 @@ private:\n \tvoid parseConstraint(const YamlObject &modeDict, int32_t id);\n \tint parseConstraintModes(const YamlObject &tuningData);\n \tint parseExposureModes(const YamlObject &tuningData);\n-\tdouble estimateInitialGain() const;\n+\tdouble estimateInitialGain(double lux) const;\n \tdouble constraintClampGain(uint32_t constraintModeIndex,\n \t\t\t\t   const Histogram &hist,\n \t\t\t\t   double gain);\n@@ -84,7 +85,7 @@ private:\n \n \tuint64_t frameCount_;\n \tutils::Duration filteredExposure_;\n-\tdouble relativeLuminanceTarget_;\n+\tPwl relativeLuminanceTarget_;\n \n \tstd::map<int32_t, std::vector<AgcConstraint>> constraintModes_;\n \tstd::map<int32_t, std::shared_ptr<ExposureModeHelper>> exposureModeHelpers_;\ndiff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\nindex 3bbafd978..e9f1f2095 100644\n--- a/src/ipa/rkisp1/algorithms/agc.cpp\n+++ b/src/ipa/rkisp1/algorithms/agc.cpp\n@@ -379,12 +379,15 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n \tdouble analogueGain = frameContext.sensor.gain;\n \tutils::Duration effectiveExposureValue = exposureTime * analogueGain;\n \n+\t/* \\todo Plumb in the lux value. Requires a lux algo + tuning */\n+\tdouble lux = 400;\n+\n \tutils::Duration shutterTime;\n \tdouble aGain, dGain;\n \tstd::tie(shutterTime, aGain, dGain) =\n \t\tcalculateNewEv(context.activeState.agc.constraintMode,\n \t\t\t       context.activeState.agc.exposureMode,\n-\t\t\t       hist, effectiveExposureValue);\n+\t\t\t       hist, effectiveExposureValue, lux);\n \n \tLOG(RkISP1Agc, Debug)\n \t\t<< \"Divided up shutter, analogue gain and digital gain are \"\n",
    "prefixes": [
        "v5",
        "2/3"
    ]
}