{"id":25977,"url":"https://patchwork.libcamera.org/api/1.1/patches/25977/?format=json","web_url":"https://patchwork.libcamera.org/patch/25977/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260127162923.112675-1-mzamazal@redhat.com>","date":"2026-01-27T16:29:23","name":"[v2] libcamera: simple: Fix black level offsets in AWB","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"452550bfe199e2f237b3c154aebd04ad7176591a","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/1.1/people/177/?format=json","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/25977/mbox/","series":[{"id":5744,"url":"https://patchwork.libcamera.org/api/1.1/series/5744/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5744","date":"2026-01-27T16:29:23","name":"[v2] libcamera: simple: Fix black level offsets in AWB","version":2,"mbox":"https://patchwork.libcamera.org/series/5744/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/25977/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/25977/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 07A3AC3220\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 27 Jan 2026 16:29:39 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D364461FCE;\n\tTue, 27 Jan 2026 17:29:37 +0100 (CET)","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 E4FE561FBF\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 27 Jan 2026 17:29:35 +0100 (CET)","from mx-prod-mc-03.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-488-CkBWDK8CPnSoAlZyAg0h7g-1;\n\tTue, 27 Jan 2026 11:29:30 -0500","from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com\n\t(mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com\n\t[10.30.177.12])\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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTPS id 990D91955D84; Tue, 27 Jan 2026 16:29:29 +0000 (UTC)","from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.174])\n\tby mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTP id 765C019560B4; Tue, 27 Jan 2026 16:29:27 +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=\"YrbPC0sx\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1769531374;\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\tbh=CfE+iaifG5p+AUU6jmm7bJcSPuvfkxhGGbqYcXNmAZY=;\n\tb=YrbPC0sxHQqJ6gLVrpapaNq4UIpyD36RBTjQxLbYb6J1cttoXiPrfQoSvqcfohu4WFLoBZ\n\tjeHvvvlRSjMMso53P8RGIBwwBKo4g+7k8LU90sut945ejuhUYTjzbXJi7MPoW7/OMJJM+k\n\twHgFb+VEHKUkxJ9QACHqnHeYNAbGQEk=","X-MC-Unique":"CkBWDK8CPnSoAlZyAg0h7g-1","X-Mimecast-MFC-AGG-ID":"CkBWDK8CPnSoAlZyAg0h7g_1769531369","From":"Milan Zamazal <mzamazal@redhat.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Milan Zamazal <mzamazal@redhat.com>,\n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tRobert Mader <robert.mader@collabora.com>","Subject":"[PATCH v2] libcamera: simple: Fix black level offsets in AWB","Date":"Tue, 27 Jan 2026 17:29:23 +0100","Message-ID":"<20260127162923.112675-1-mzamazal@redhat.com>","MIME-Version":"1.0","X-Scanned-By":"MIMEDefang 3.0 on 10.30.177.12","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"AR0T1hg8bMmlJS5pbmMa3JUXsZgDbg28kiC8Zllm8eU_1769531369","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":"The black level offset subtracted in AWB is wrong.  It assumes that the\nstats contain sums of the individual colour pixels.  But they actually\ncontain sums of the colour channels of larger \"superpixels\" consisting\nof the individual colour pixels.  Each of the RGB colour values and the\ncomputed luminosity (a histogram entry) are added once to the stats per\nsuch a superpixel.  This means the offset computed from the black level\nand the number of pixels should be used as it is, not divided.\n\nThe patch fixes the subtracted offset.  Since the evaluation is the same\nfor all the three colours now, the individual class variables are\nreplaced with a single RGB variable.\n\nFixes: 4e13c6f55bd667 (\"Honor black level in AWB\")\nSigned-off-by: Milan Zamazal <mzamazal@redhat.com>\n---\n .../internal/software_isp/swisp_stats.h          | 16 +++++-----------\n src/ipa/simple/algorithms/awb.cpp                | 10 ++++------\n src/libcamera/software_isp/swstats_cpu.cpp       | 10 ++++------\n 3 files changed, 13 insertions(+), 23 deletions(-)","diff":"diff --git a/include/libcamera/internal/software_isp/swisp_stats.h b/include/libcamera/internal/software_isp/swisp_stats.h\nindex 3c9860185..d9d0d9be8 100644\n--- a/include/libcamera/internal/software_isp/swisp_stats.h\n+++ b/include/libcamera/internal/software_isp/swisp_stats.h\n@@ -10,6 +10,8 @@\n #include <array>\n #include <stdint.h>\n \n+#include \"libcamera/internal/vector.h\"\n+\n namespace libcamera {\n \n /**\n@@ -26,17 +28,9 @@ struct SwIspStats {\n \t */\n \tbool valid;\n \t/**\n-\t * \\brief Holds the sum of all sampled red pixels\n-\t */\n-\tuint64_t sumR_;\n-\t/**\n-\t * \\brief Holds the sum of all sampled green pixels\n-\t */\n-\tuint64_t sumG_;\n-\t/**\n-\t * \\brief Holds the sum of all sampled blue pixels\n+\t * \\brief Sums of colour channels of all the sampled pixels\n \t */\n-\tuint64_t sumB_;\n+\tRGB<uint64_t> sum_;\n \t/**\n \t * \\brief Number of bins in the yHistogram\n \t */\n@@ -46,7 +40,7 @@ struct SwIspStats {\n \t */\n \tusing Histogram = std::array<uint32_t, kYHistogramSize>;\n \t/**\n-\t * \\brief A histogram of luminance values\n+\t * \\brief A histogram of luminance values of all the sampled pixels\n \t */\n \tHistogram yHistogram;\n };\ndiff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp\nindex 0080865aa..75e4ae4a4 100644\n--- a/src/ipa/simple/algorithms/awb.cpp\n+++ b/src/ipa/simple/algorithms/awb.cpp\n@@ -1,6 +1,6 @@\n /* SPDX-License-Identifier: LGPL-2.1-or-later */\n /*\n- * Copyright (C) 2024, Red Hat Inc.\n+ * Copyright (C) 2024-2026 Red Hat Inc.\n  *\n  * Auto white balance\n  */\n@@ -73,9 +73,7 @@ void Awb::process(IPAContext &context,\n \t\thistogram.begin(), histogram.end(), uint64_t(0));\n \tconst uint64_t offset = blackLevel * nPixels;\n \tconst uint64_t minValid = 1;\n-\tconst uint64_t sumR = stats->sumR_ > offset / 4 ? stats->sumR_ - offset / 4 : minValid;\n-\tconst uint64_t sumG = stats->sumG_ > offset / 2 ? stats->sumG_ - offset / 2 : minValid;\n-\tconst uint64_t sumB = stats->sumB_ > offset / 4 ? stats->sumB_ - offset / 4 : minValid;\n+\tconst RGB<uint64_t> sum = (stats->sum_ - offset).max(minValid);\n \n \t/*\n \t * Calculate red and blue gains for AWB.\n@@ -83,9 +81,9 @@ void Awb::process(IPAContext &context,\n \t */\n \tauto &gains = context.activeState.awb.gains;\n \tgains = { {\n-\t\tsumR <= sumG / 4 ? 4.0f : static_cast<float>(sumG) / sumR,\n+\t\tsum.r() <= sum.g() / 4 ? 4.0f : static_cast<float>(sum.g()) / sum.r(),\n \t\t1.0,\n-\t\tsumB <= sumG / 4 ? 4.0f : static_cast<float>(sumG) / sumB,\n+\t\tsum.b() <= sum.g() / 4 ? 4.0f : static_cast<float>(sum.g()) / sum.b(),\n \t} };\n \n \tRGB<double> rgbGains{ { 1 / gains.r(), 1 / gains.g(), 1 / gains.b() } };\ndiff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp\nindex c931edb41..5c3011a7f 100644\n--- a/src/libcamera/software_isp/swstats_cpu.cpp\n+++ b/src/libcamera/software_isp/swstats_cpu.cpp\n@@ -185,9 +185,9 @@ static constexpr unsigned int kBlueYMul = 29; /* 0.114 * 256 */\n \tstats_.yHistogram[yVal * SwIspStats::kYHistogramSize / (256 * 256 * (div))]++;\n \n #define SWSTATS_FINISH_LINE_STATS() \\\n-\tstats_.sumR_ += sumR;       \\\n-\tstats_.sumG_ += sumG;       \\\n-\tstats_.sumB_ += sumB;\n+\tstats_.sum_.r() += sumR;    \\\n+\tstats_.sum_.g() += sumG;    \\\n+\tstats_.sum_.b() += sumB;\n \n void SwStatsCpu::statsBGGR8Line0(const uint8_t *src[])\n {\n@@ -332,9 +332,7 @@ void SwStatsCpu::startFrame(uint32_t frame)\n \tif (window_.width == 0)\n \t\tLOG(SwStatsCpu, Error) << \"Calling startFrame() without setWindow()\";\n \n-\tstats_.sumR_ = 0;\n-\tstats_.sumB_ = 0;\n-\tstats_.sumG_ = 0;\n+\tstats_.sum_ = RGB<uint64_t>({ 0, 0, 0 });\n \tstats_.yHistogram.fill(0);\n }\n \n","prefixes":["v2"]}