Show a patch.

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

{
    "id": 21569,
    "url": "https://patchwork.libcamera.org/api/patches/21569/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/21569/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/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": "<20241009193318.2394762-2-mzamazal@redhat.com>",
    "date": "2024-10-09T19:33:16",
    "name": "[v2,1/2] libcamera: software_isp: Add contrast algorithm",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "420fef05b0e9c568b3f4e12d1c2c27bf8a5a76c9",
    "submitter": {
        "id": 177,
        "url": "https://patchwork.libcamera.org/api/people/177/?format=api",
        "name": "Milan Zamazal",
        "email": "mzamazal@redhat.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/21569/mbox/",
    "series": [
        {
            "id": 4677,
            "url": "https://patchwork.libcamera.org/api/series/4677/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4677",
            "date": "2024-10-09T19:33:15",
            "name": "Add contrast control to software ISP",
            "version": 2,
            "mbox": "https://patchwork.libcamera.org/series/4677/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/21569/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/21569/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 94C9FC32DE\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  9 Oct 2024 19:33:39 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4331D65370;\n\tWed,  9 Oct 2024 21:33:39 +0200 (CEST)",
            "from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5033163538\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  9 Oct 2024 21:33:37 +0200 (CEST)",
            "from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com\n\t(ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63])\n\tby relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n\tcipher=TLS_AES_256_GCM_SHA384) id us-mta-140-4RhMX9aCNpyD-Pr3Q_07Rw-1;\n\tWed, 09 Oct 2024 15:33:32 -0400",
            "from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com\n\t(mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\tkey-exchange X25519 server-signature RSA-PSS (2048 bits)\n\tserver-digest SHA256) (No client certificate requested)\n\tby mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTPS id EF95F19560A1; Wed,  9 Oct 2024 19:33:31 +0000 (UTC)",
            "from nuthatch.redhat.com (unknown [10.45.224.78])\n\tby mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTP id 651EC300018D; Wed,  9 Oct 2024 19:33:30 +0000 (UTC)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"WSQgfGqe\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1728502416;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tcontent-transfer-encoding:content-transfer-encoding:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=4s/TcOik+viXMR7VDGt05/Gtrx4cZxUaxgVi26AI9U4=;\n\tb=WSQgfGqeFiK4jFdSCIEn+XPxm9dRyIaqq7I3ycnzwXxOFDRSoQwsUn+WDClLg6+KD6LIrj\n\tIKbA1Zs0/TiGWabpcqupWLDhfto4BBhMzrGK5oH7Q06TV9bSep4E4Rr5T8uQtY5dNhsncP\n\tt8RkKpQN+4XCsQECw1CLYCLPqecQxh4=",
        "X-MC-Unique": "4RhMX9aCNpyD-Pr3Q_07Rw-1",
        "From": "Milan Zamazal <mzamazal@redhat.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Milan Zamazal <mzamazal@redhat.com>,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>",
        "Subject": "[PATCH v2 1/2] libcamera: software_isp: Add contrast algorithm",
        "Date": "Wed,  9 Oct 2024 21:33:16 +0200",
        "Message-ID": "<20241009193318.2394762-2-mzamazal@redhat.com>",
        "In-Reply-To": "<20241009193318.2394762-1-mzamazal@redhat.com>",
        "References": "<20241009193318.2394762-1-mzamazal@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.4",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-Originator": "redhat.com",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain; charset=\"US-ASCII\"; x-default=true",
        "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": "Software ISP is currently fully automatic and doesn't allow image\nmodifications by explicitly set control values.  The user has no means\nto make the image looking better.\n\nThis patch introduces contrast control algorithm, which can improve\ne.g. a flat looking image.  Based on the provided contrast value with a\nrange 0..infinity and 1.0 being the normal value, it applies a simple\nS-curve modification to the image.  The contrast algorithm just handles\nthe provided values, while the S-curve is applied in the gamma algorithm\non the computed gamma curve whenever the contrast value changes.  Since\nthe algorithm is applied only on the lookup table already present, its\noverhead is negligible.\n\nThis is a preparation patch without actually activating the contrast\nalgorithm, which will be done in the following patch.\n\nSigned-off-by: Milan Zamazal <mzamazal@redhat.com>\n---\n src/ipa/simple/algorithms/contrast.cpp | 45 ++++++++++++++++++++++++++\n src/ipa/simple/algorithms/contrast.h   | 37 +++++++++++++++++++++\n src/ipa/simple/algorithms/lut.cpp      | 20 +++++++++---\n src/ipa/simple/algorithms/meson.build  |  1 +\n src/ipa/simple/ipa_context.h           |  7 ++++\n 5 files changed, 105 insertions(+), 5 deletions(-)\n create mode 100644 src/ipa/simple/algorithms/contrast.cpp\n create mode 100644 src/ipa/simple/algorithms/contrast.h",
    "diff": "diff --git a/src/ipa/simple/algorithms/contrast.cpp b/src/ipa/simple/algorithms/contrast.cpp\nnew file mode 100644\nindex 000000000..1a2c14cf9\n--- /dev/null\n+++ b/src/ipa/simple/algorithms/contrast.cpp\n@@ -0,0 +1,45 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024, Red Hat Inc.\n+ *\n+ * Contrast adjustment\n+ */\n+\n+#include \"contrast.h\"\n+\n+#include <optional>\n+\n+#include <libcamera/base/log.h>\n+\n+#include \"control_ids.h\"\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(IPASoftContrast)\n+\n+namespace ipa::soft::algorithms {\n+\n+int Contrast::configure(typename Module::Context &context,\n+\t\t\t[[maybe_unused]] const typename Module::Config &configInfo)\n+{\n+\tcontext.activeState.knobs.contrast = std::optional<double>();\n+\treturn 0;\n+}\n+\n+void Contrast::queueRequest(typename Module::Context &context,\n+\t\t\t    [[maybe_unused]] const uint32_t frame,\n+\t\t\t    [[maybe_unused]] typename Module::FrameContext &frameContext,\n+\t\t\t    const ControlList &controls)\n+{\n+\tconst auto &contrast = controls.get(controls::Contrast);\n+\tif (contrast.has_value()) {\n+\t\tcontext.activeState.knobs.contrast = contrast;\n+\t\tLOG(IPASoftContrast, Debug) << \"Setting contrast to \" << contrast.value();\n+\t}\n+}\n+\n+REGISTER_IPA_ALGORITHM(Contrast, \"Contrast\")\n+\n+} /* namespace ipa::soft::algorithms */\n+\n+} /* namespace libcamera */\ndiff --git a/src/ipa/simple/algorithms/contrast.h b/src/ipa/simple/algorithms/contrast.h\nnew file mode 100644\nindex 000000000..0b3933099\n--- /dev/null\n+++ b/src/ipa/simple/algorithms/contrast.h\n@@ -0,0 +1,37 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024, Red Hat Inc.\n+ *\n+ * Contrast adjustment\n+ */\n+\n+#pragma once\n+\n+#include <libcamera/controls.h>\n+\n+#include \"algorithm.h\"\n+\n+namespace libcamera {\n+\n+namespace ipa::soft::algorithms {\n+\n+class Contrast : public Algorithm\n+{\n+public:\n+\tContrast() = default;\n+\t~Contrast() = default;\n+\n+\tint configure(typename Module::Context &context,\n+\t\t      const typename Module::Config &configInfo)\n+\t\toverride;\n+\n+\tvoid queueRequest(typename Module::Context &context,\n+\t\t\t  const uint32_t frame,\n+\t\t\t  typename Module::FrameContext &frameContext,\n+\t\t\t  const ControlList &controls)\n+\t\toverride;\n+};\n+\n+} /* namespace ipa::soft::algorithms */\n+\n+} /* namespace libcamera */\ndiff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp\nindex 9744e773a..8ebc824ce 100644\n--- a/src/ipa/simple/algorithms/lut.cpp\n+++ b/src/ipa/simple/algorithms/lut.cpp\n@@ -32,16 +32,25 @@ int Lut::configure(IPAContext &context,\n void Lut::updateGammaTable(IPAContext &context)\n {\n \tauto &gammaTable = context.activeState.gamma.gammaTable;\n-\tauto blackLevel = context.activeState.blc.level;\n+\tconst auto blackLevel = context.activeState.blc.level;\n \tconst unsigned int blackIndex = blackLevel * gammaTable.size() / 256;\n+\tconst auto contrast = context.activeState.knobs.contrast.value_or(1.0);\n \n \tstd::fill(gammaTable.begin(), gammaTable.begin() + blackIndex, 0);\n \tconst float divisor = gammaTable.size() - blackIndex - 1.0;\n-\tfor (unsigned int i = blackIndex; i < gammaTable.size(); i++)\n-\t\tgammaTable[i] = UINT8_MAX * std::pow((i - blackIndex) / divisor,\n-\t\t\t\t\t\t     context.configuration.gamma);\n+\tfor (unsigned int i = blackIndex; i < gammaTable.size(); i++) {\n+\t\tdouble normalized = (i - blackIndex) / divisor;\n+\t\t/* Apply simple S-curve */\n+\t\tif (normalized < 0.5)\n+\t\t\tnormalized = 0.5 * std::pow(normalized / 0.5, contrast);\n+\t\telse\n+\t\t\tnormalized = 1.0 - 0.5 * std::pow((1.0 - normalized) / 0.5, contrast);\n+\t\tgammaTable[i] = UINT8_MAX *\n+\t\t\t\tstd::pow(normalized, context.configuration.gamma);\n+\t}\n \n \tcontext.activeState.gamma.blackLevel = blackLevel;\n+\tcontext.activeState.gamma.contrast = contrast;\n }\n \n void Lut::prepare(IPAContext &context,\n@@ -55,7 +64,8 @@ void Lut::prepare(IPAContext &context,\n \t * observed, it's not permanently prone to minor fluctuations or\n \t * rounding errors.\n \t */\n-\tif (context.activeState.gamma.blackLevel != context.activeState.blc.level)\n+\tif (context.activeState.gamma.blackLevel != context.activeState.blc.level ||\n+\t    context.activeState.gamma.contrast != context.activeState.knobs.contrast)\n \t\tupdateGammaTable(context);\n \n \tauto &gains = context.activeState.gains;\ndiff --git a/src/ipa/simple/algorithms/meson.build b/src/ipa/simple/algorithms/meson.build\nindex 37a2eb534..d75a7b2a1 100644\n--- a/src/ipa/simple/algorithms/meson.build\n+++ b/src/ipa/simple/algorithms/meson.build\n@@ -4,5 +4,6 @@ soft_simple_ipa_algorithms = files([\n     'awb.cpp',\n     'agc.cpp',\n     'blc.cpp',\n+    'contrast.cpp',\n     'lut.cpp',\n ])\ndiff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h\nindex 3519f20f6..5118d6abf 100644\n--- a/src/ipa/simple/ipa_context.h\n+++ b/src/ipa/simple/ipa_context.h\n@@ -8,8 +8,11 @@\n #pragma once\n \n #include <array>\n+#include <optional>\n #include <stdint.h>\n \n+#include <libcamera/controls.h>\n+\n #include <libipa/fc_queue.h>\n \n namespace libcamera {\n@@ -44,7 +47,11 @@ struct IPAActiveState {\n \tstruct {\n \t\tstd::array<double, kGammaLookupSize> gammaTable;\n \t\tuint8_t blackLevel;\n+\t\tdouble contrast;\n \t} gamma;\n+\tstruct {\n+\t\tstd::optional<double> contrast; // 0..inf, 1 = neutral\n+\t} knobs;\n };\n \n struct IPAFrameContext : public FrameContext {\n",
    "prefixes": [
        "v2",
        "1/2"
    ]
}