From patchwork Tue Jan 27 12:37:28 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 25975 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 D8EDCC3220 for ; Tue, 27 Jan 2026 12:37:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 00A4661FC8; Tue, 27 Jan 2026 13:37:38 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="GQCy6v0E"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 906F761FBF for ; Tue, 27 Jan 2026 13:37:37 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1769517456; 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=t6Z+J8sVeD8URo7A7kyv63jK28bZIrhzKlJ56AnsIQU=; b=GQCy6v0EOzruv4hu8W86IXHfsICwFOeVv9Vv2vtzYhRaigmmjqNy78l7gDbX1qPkTCn8gg d5FqSV21gzksrGxp4oT8XwlDQcWuKyKPtiR/3DvMc9IBD9nZiDlfv4uPkrB2uVOCBIBCTX 1WrvMIVVsv3GKarjE4VlzdTeA7FOs3Y= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-355-krBOJFbPOM26pODRmibDdw-1; Tue, 27 Jan 2026 07:37:34 -0500 X-MC-Unique: krBOJFbPOM26pODRmibDdw-1 X-Mimecast-MFC-AGG-ID: krBOJFbPOM26pODRmibDdw_1769517454 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id F41A31800624 for ; Tue, 27 Jan 2026 12:37:33 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.174]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id BEFD61956095; Tue, 27 Jan 2026 12:37:32 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal Subject: [PATCH] libcamera: simple: Fix black level offsets in AWB Date: Tue, 27 Jan 2026 13:37:28 +0100 Message-ID: <20260127123728.70513-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Phc-8iQdk99i1J1PsyRNRMIXdzmCNsWE2s5NQ4-rqmA_1769517454 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 it is the same for all the three colours, a SwIspStats helper method returning an RGB instance is introduced. The individual colour variables are still retained in SwIspStats for maximum efficiency when gathering the stats. SwIspStats docstrings are changed to avoid the original confusion. Fixes: 4e13c6f55bd667 ("Honor black level in AWB") Signed-off-by: Milan Zamazal --- .../internal/software_isp/swisp_stats.h | 17 +++++++++++++---- src/ipa/simple/algorithms/awb.cpp | 10 ++++------ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/include/libcamera/internal/software_isp/swisp_stats.h b/include/libcamera/internal/software_isp/swisp_stats.h index 3c9860185..f8816209f 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,24 @@ struct SwIspStats { */ bool valid; /** - * \brief Holds the sum of all sampled red pixels + * \brief Holds the sum of red channels of all the sampled pixels */ uint64_t sumR_; /** - * \brief Holds the sum of all sampled green pixels + * \brief Holds the sum of green channels of all the sampled pixels */ uint64_t sumG_; /** - * \brief Holds the sum of all sampled blue pixels + * \brief Holds the sum of blue channels of all the sampled pixels */ uint64_t sumB_; + /** + * \brief Return the sums of colour channels of all the sampled pixels + */ + RGB rgbSum() const + { + return RGB({ sumR_, sumG_, sumB_ }); + } /** * \brief Number of bins in the yHistogram */ @@ -46,7 +55,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..4c8bfd2de 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->rgbSum() - 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() } };