From patchwork Tue Jan 27 16:29:23 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 25977 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 07A3AC3220 for ; Tue, 27 Jan 2026 16:29:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D364461FCE; Tue, 27 Jan 2026 17:29:37 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="YrbPC0sx"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E4FE561FBF for ; Tue, 27 Jan 2026 17:29:35 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1769531374; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=CfE+iaifG5p+AUU6jmm7bJcSPuvfkxhGGbqYcXNmAZY=; b=YrbPC0sxHQqJ6gLVrpapaNq4UIpyD36RBTjQxLbYb6J1cttoXiPrfQoSvqcfohu4WFLoBZ jeHvvvlRSjMMso53P8RGIBwwBKo4g+7k8LU90sut945ejuhUYTjzbXJi7MPoW7/OMJJM+k wHgFb+VEHKUkxJ9QACHqnHeYNAbGQEk= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-488-CkBWDK8CPnSoAlZyAg0h7g-1; Tue, 27 Jan 2026 11:29:30 -0500 X-MC-Unique: CkBWDK8CPnSoAlZyAg0h7g-1 X-Mimecast-MFC-AGG-ID: CkBWDK8CPnSoAlZyAg0h7g_1769531369 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 990D91955D84; Tue, 27 Jan 2026 16:29:29 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.174]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 765C019560B4; Tue, 27 Jan 2026 16:29:27 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Laurent Pinchart , Robert Mader 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-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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The black level offset subtracted in AWB is wrong. It assumes that the stats contain sums of the individual colour pixels. But they actually contain sums of the colour channels of larger "superpixels" consisting of the individual colour pixels. Each of the RGB colour values and the computed luminosity (a histogram entry) are added once to the stats per such a superpixel. This means the offset computed from the black level and the number of pixels should be used as it is, not divided. The patch fixes the subtracted offset. Since the evaluation is the same for all the three colours now, the individual class variables are replaced with a single RGB variable. Fixes: 4e13c6f55bd667 ("Honor black level in AWB") Signed-off-by: Milan Zamazal Reviewed-by: Laurent Pinchart Reviewed-by: Robert Mader Tested-by: Robert Mader --- .../internal/software_isp/swisp_stats.h | 16 +++++----------- src/ipa/simple/algorithms/awb.cpp | 10 ++++------ src/libcamera/software_isp/swstats_cpu.cpp | 10 ++++------ 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/include/libcamera/internal/software_isp/swisp_stats.h b/include/libcamera/internal/software_isp/swisp_stats.h index 3c9860185..d9d0d9be8 100644 --- a/include/libcamera/internal/software_isp/swisp_stats.h +++ b/include/libcamera/internal/software_isp/swisp_stats.h @@ -10,6 +10,8 @@ #include #include +#include "libcamera/internal/vector.h" + namespace libcamera { /** @@ -26,17 +28,9 @@ struct SwIspStats { */ bool valid; /** - * \brief Holds the sum of all sampled red pixels - */ - uint64_t sumR_; - /** - * \brief Holds the sum of all sampled green pixels - */ - uint64_t sumG_; - /** - * \brief Holds the sum of all sampled blue pixels + * \brief Sums of colour channels of all the sampled pixels */ - uint64_t sumB_; + RGB sum_; /** * \brief Number of bins in the yHistogram */ @@ -46,7 +40,7 @@ struct SwIspStats { */ using Histogram = std::array; /** - * \brief A histogram of luminance values + * \brief A histogram of luminance values of all the sampled pixels */ Histogram yHistogram; }; diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp index 0080865aa..75e4ae4a4 100644 --- a/src/ipa/simple/algorithms/awb.cpp +++ b/src/ipa/simple/algorithms/awb.cpp @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ /* - * Copyright (C) 2024, Red Hat Inc. + * Copyright (C) 2024-2026 Red Hat Inc. * * Auto white balance */ @@ -73,9 +73,7 @@ void Awb::process(IPAContext &context, histogram.begin(), histogram.end(), uint64_t(0)); const uint64_t offset = blackLevel * nPixels; const uint64_t minValid = 1; - const uint64_t sumR = stats->sumR_ > offset / 4 ? stats->sumR_ - offset / 4 : minValid; - const uint64_t sumG = stats->sumG_ > offset / 2 ? stats->sumG_ - offset / 2 : minValid; - const uint64_t sumB = stats->sumB_ > offset / 4 ? stats->sumB_ - offset / 4 : minValid; + const RGB sum = (stats->sum_ - offset).max(minValid); /* * Calculate red and blue gains for AWB. @@ -83,9 +81,9 @@ void Awb::process(IPAContext &context, */ auto &gains = context.activeState.awb.gains; gains = { { - sumR <= sumG / 4 ? 4.0f : static_cast(sumG) / sumR, + sum.r() <= sum.g() / 4 ? 4.0f : static_cast(sum.g()) / sum.r(), 1.0, - sumB <= sumG / 4 ? 4.0f : static_cast(sumG) / sumB, + sum.b() <= sum.g() / 4 ? 4.0f : static_cast(sum.g()) / sum.b(), } }; RGB rgbGains{ { 1 / gains.r(), 1 / gains.g(), 1 / gains.b() } }; diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp index c931edb41..5c3011a7f 100644 --- a/src/libcamera/software_isp/swstats_cpu.cpp +++ b/src/libcamera/software_isp/swstats_cpu.cpp @@ -185,9 +185,9 @@ static constexpr unsigned int kBlueYMul = 29; /* 0.114 * 256 */ stats_.yHistogram[yVal * SwIspStats::kYHistogramSize / (256 * 256 * (div))]++; #define SWSTATS_FINISH_LINE_STATS() \ - stats_.sumR_ += sumR; \ - stats_.sumG_ += sumG; \ - stats_.sumB_ += sumB; + stats_.sum_.r() += sumR; \ + stats_.sum_.g() += sumG; \ + stats_.sum_.b() += sumB; void SwStatsCpu::statsBGGR8Line0(const uint8_t *src[]) { @@ -332,9 +332,7 @@ void SwStatsCpu::startFrame(uint32_t frame) if (window_.width == 0) LOG(SwStatsCpu, Error) << "Calling startFrame() without setWindow()"; - stats_.sumR_ = 0; - stats_.sumB_ = 0; - stats_.sumG_ = 0; + stats_.sum_ = RGB({ 0, 0, 0 }); stats_.yHistogram.fill(0); }