From patchwork Mon Mar 24 17:07:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 23002 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 9799BC3213 for ; Mon, 24 Mar 2025 17:08:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4CD8E68954; Mon, 24 Mar 2025 18:08:18 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="C9KU1Mhq"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3FBB868945 for ; Mon, 24 Mar 2025 18:08:16 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:854:5bc6:b2a7:e242]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8D0E7455; Mon, 24 Mar 2025 18:06:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1742835989; bh=xWqkUF4YwfxJrRbwmW1md+m0MlZxkpK3+kTodBpdSKc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=C9KU1MhqVzv5FL1vYTLTnEyxvKq/sb01u8HPdM+qbART+gQuxB6plRdcbxTDffm0M wCnGEP49/d6fgQPx3MdclaMWMeIKQa+swMvp8XU7gNllrC4zUGdDFJssFDm3cpj3n0 J7WWsasVfUfdU+h803HZVu02ZLmIrE02ZgR+5Ofg= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug Subject: [PATCH 1/5] test: ipa: libipa: Add histogram tests Date: Mon, 24 Mar 2025 18:07:36 +0100 Message-ID: <20250324170803.103296-2-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250324170803.103296-1-stefan.klug@ideasonboard.com> References: <20250324170803.103296-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 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" Add some basic tests for the histogram class. Signed-off-by: Stefan Klug Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- test/ipa/libipa/histogram.cpp | 53 +++++++++++++++++++++++++++++++++++ test/ipa/libipa/meson.build | 1 + 2 files changed, 54 insertions(+) create mode 100644 test/ipa/libipa/histogram.cpp diff --git a/test/ipa/libipa/histogram.cpp b/test/ipa/libipa/histogram.cpp new file mode 100644 index 000000000000..220a329e33b3 --- /dev/null +++ b/test/ipa/libipa/histogram.cpp @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024, Ideas on Board Oy + * + * Histogram tests + */ + +#include "../src/ipa/libipa/histogram.h" + +#include +#include +#include +#include + +#include "test.h" + +using namespace std; +using namespace libcamera; +using namespace ipa; + +#define ASSERT_EQ(a, b) \ + if (!((a) == (b))) { \ + printf(#a " != " #b "\n"); \ + return TestFail; \ + } + +class HistogramTest : public Test +{ +protected: + int run() + { + auto hist = Histogram({ { 50, 50 } }); + + ASSERT_EQ(hist.bins(), 2); + ASSERT_EQ(hist.total(), 100); + + ASSERT_EQ(hist.cumulativeFrequency(1.0), 50); + ASSERT_EQ(hist.cumulativeFrequency(1.5), 75); + ASSERT_EQ(hist.cumulativeFrequency(2.0), 100); + + ASSERT_EQ(hist.quantile(0.0), 0.0); + ASSERT_EQ(hist.quantile(1.0), 2.0); + ASSERT_EQ(hist.quantile(0.5), 1.0); + + ASSERT_EQ(hist.interQuantileMean(0.0, 1.0), 1.0); + ASSERT_EQ(hist.interQuantileMean(0.0, 0.5), 0.5); + ASSERT_EQ(hist.interQuantileMean(0.5, 1.0), 1.5); + + return TestPass; + } +}; + +TEST_REGISTER(HistogramTest) diff --git a/test/ipa/libipa/meson.build b/test/ipa/libipa/meson.build index eaf4b49a187c..f094c1593f1b 100644 --- a/test/ipa/libipa/meson.build +++ b/test/ipa/libipa/meson.build @@ -2,6 +2,7 @@ libipa_test = [ {'name': 'fixedpoint', 'sources': ['fixedpoint.cpp']}, + {'name': 'histogram', 'sources': ['histogram.cpp']}, {'name': 'interpolator', 'sources': ['interpolator.cpp']}, ] From patchwork Mon Mar 24 17:07:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 23003 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 2AF6CC3213 for ; Mon, 24 Mar 2025 17:08:21 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D266968959; Mon, 24 Mar 2025 18:08:20 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ehz8lwSq"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D394B68945 for ; Mon, 24 Mar 2025 18:08:18 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:854:5bc6:b2a7:e242]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 50E78A8F; Mon, 24 Mar 2025 18:06:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1742835992; bh=rjzPA6Us67ZjTb/h97K3bGEFgnhDfi+yLIZKMoqHl98=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ehz8lwSqBj+OUyB8X9cNv07AnpAQtNh7Te3saFBNbFkK27z0u4epv0CSlql/sRbL3 E+hAu54DBE44uXQLCAuyvIKIiWL67SI72xPPTRLwEZOIgs3DuaWa7z//y/OnQvSzAq xvbH2d8aIxN2yWvulEEk/yEW4SdAH8j09ALaxjOg= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug Subject: [PATCH 2/5] libipa: histogram: Fix quantile() calculation for fractional results Date: Mon, 24 Mar 2025 18:07:37 +0100 Message-ID: <20250324170803.103296-3-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250324170803.103296-1-stefan.klug@ideasonboard.com> References: <20250324170803.103296-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 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 calculation of the frac variable is based solely on integers and therefore results in the fractional part being either 0 or 1. In the original code from RaspberryPi this is mitigated by casting the nominator to a double. This works for most cases, but fails when q is very small because of the quantization introduced by item being an integer. Fix both issues by doing the full calculation in double. Signed-off-by: Stefan Klug Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- src/ipa/libipa/histogram.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ipa/libipa/histogram.cpp b/src/ipa/libipa/histogram.cpp index 10e44b54a0cf..c19a4cbbf3cd 100644 --- a/src/ipa/libipa/histogram.cpp +++ b/src/ipa/libipa/histogram.cpp @@ -130,7 +130,8 @@ double Histogram::quantile(double q, uint32_t first, uint32_t last) const if (cumulative_[first + 1] == cumulative_[first]) frac = 0; else - frac = (item - cumulative_[first]) / (cumulative_[first + 1] - cumulative_[first]); + frac = (q * total() - cumulative_[first]) / + (cumulative_[first + 1] - cumulative_[first]); return first + frac; } From patchwork Mon Mar 24 17:07:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 23004 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 26D91C3213 for ; Mon, 24 Mar 2025 17:08:24 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C0D5A6895E; Mon, 24 Mar 2025 18:08:23 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ADBiKAQL"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1D51268958 for ; Mon, 24 Mar 2025 18:08:22 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:854:5bc6:b2a7:e242]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 873C4A8F; Mon, 24 Mar 2025 18:06:35 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1742835995; bh=TSLreD3TRry1QHtl7vm4ovSrUPdYKLwxukx1k3nTb0o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ADBiKAQLvOzfV9+/3prRdmuN3hdTUcsnHLHE1GhTC7gg5Qqi3wxAQfu6vetxQrUd3 j+0puwjqienQ9KkSfWScjy4E2eO1qXIFsIiHBJ4LYtDbR5DMeowXrzC+WOnvevRFPF kJzdbzlwV94CUYyPQik5i/CVHic2M+qcL5E2QfHs= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug Subject: [PATCH 3/5] test: ipa: libipa: histogram: Add tests for quantile() returning a fraction Date: Mon, 24 Mar 2025 18:07:38 +0100 Message-ID: <20250324170803.103296-4-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250324170803.103296-1-stefan.klug@ideasonboard.com> References: <20250324170803.103296-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 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" Add tests for quantile() returning a fractional value. These cases were fixed in the last commit. Signed-off-by: Stefan Klug Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- test/ipa/libipa/histogram.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/ipa/libipa/histogram.cpp b/test/ipa/libipa/histogram.cpp index 220a329e33b3..b96626054af0 100644 --- a/test/ipa/libipa/histogram.cpp +++ b/test/ipa/libipa/histogram.cpp @@ -42,10 +42,19 @@ protected: ASSERT_EQ(hist.quantile(1.0), 2.0); ASSERT_EQ(hist.quantile(0.5), 1.0); + /* Test quantile in the middle of a bin. */ + ASSERT_EQ(hist.quantile(0.75), 1.5); + + /* Test quantile smaller than the smallest histogram step. */ + ASSERT_EQ(hist.quantile(0.001), 0.002); + ASSERT_EQ(hist.interQuantileMean(0.0, 1.0), 1.0); ASSERT_EQ(hist.interQuantileMean(0.0, 0.5), 0.5); ASSERT_EQ(hist.interQuantileMean(0.5, 1.0), 1.5); + /* Test quantile means that are in the middle of the bins */ + ASSERT_EQ(hist.interQuantileMean(0.25, 0.75), 1.0); + return TestPass; } }; From patchwork Mon Mar 24 17:07:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 23005 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 F00EBC3213 for ; Mon, 24 Mar 2025 17:08:27 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AE3F76895F; Mon, 24 Mar 2025 18:08:27 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Vap0Xg5G"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 693CA6895D for ; Mon, 24 Mar 2025 18:08:25 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:854:5bc6:b2a7:e242]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CDA5AA8F; Mon, 24 Mar 2025 18:06:38 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1742835998; bh=0uGFCAEhZMyiQcNIKO7XXs1LGnUKZrRebehhUvhFAsU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Vap0Xg5GjqNzJwi3qdv1hBSge11DQmlaes9qOJt6I/StWxsJqSgrl1x777XcLBnjL stuuF96Fr1ikPqVbeRePex/+DO5k+KGJ51IcLgRJ21P+u/oHqSwe5kQiMcowFUSEgY gbs6RFeGJ3pdvI6vnyQTTQuk4PEbmnjPtfLlxcnM= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug Subject: [PATCH 4/5] libipa: histogram: Fix interQuantileMean() for small ranges Date: Mon, 24 Mar 2025 18:07:39 +0100 Message-ID: <20250324170803.103296-5-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250324170803.103296-1-stefan.klug@ideasonboard.com> References: <20250324170803.103296-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 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 interQuantileMean() is supposed to return a weighted mean value between two quantiles. This works for reasonably fine histograms, but fails for coarse histograms and small quantile ranges because the weight is always taken from the lower border of the bin. Fix that by rewriting the algorithm to calculate a lower and upper bound for every (partial) bin that goes into the mean calculation and weight the bins by the middle of these bounds. Signed-off-by: Stefan Klug Acked-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- src/ipa/libipa/histogram.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/ipa/libipa/histogram.cpp b/src/ipa/libipa/histogram.cpp index c19a4cbbf3cd..31f017af3458 100644 --- a/src/ipa/libipa/histogram.cpp +++ b/src/ipa/libipa/histogram.cpp @@ -153,22 +153,24 @@ double Histogram::interQuantileMean(double lowQuantile, double highQuantile) con double lowPoint = quantile(lowQuantile); /* Proportion of pixels which lies below highQuantile */ double highPoint = quantile(highQuantile, static_cast(lowPoint)); - double sumBinFreq = 0, cumulFreq = 0; + double sumBinFreq = 0; + double cumulFreq = 0; + + for (int bin = std::floor(lowPoint); bin < std::ceil(highPoint); bin++) { + double lowBound = std::max(static_cast(bin), lowPoint); + double highBound = std::min(static_cast(bin + 1), highPoint); - for (double p_next = floor(lowPoint) + 1.0; - p_next <= ceil(highPoint); - lowPoint = p_next, p_next += 1.0) { - int bin = floor(lowPoint); double freq = (cumulative_[bin + 1] - cumulative_[bin]) - * (std::min(p_next, highPoint) - lowPoint); + * (highBound - lowBound); /* Accumulate weighted bin */ - sumBinFreq += bin * freq; + sumBinFreq += 0.5 * (highBound + lowBound) * freq; + /* Accumulate weights */ cumulFreq += freq; } - /* add 0.5 to give an average for bin mid-points */ - return sumBinFreq / cumulFreq + 0.5; + + return sumBinFreq / cumulFreq; } } /* namespace ipa */ From patchwork Mon Mar 24 17:07:40 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 23006 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 A768EC3285 for ; Mon, 24 Mar 2025 17:08:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4C1EA68966; Mon, 24 Mar 2025 18:08:29 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="k1w1xO9r"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B89D168963 for ; Mon, 24 Mar 2025 18:08:27 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:854:5bc6:b2a7:e242]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 38529455; Mon, 24 Mar 2025 18:06:41 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1742836001; bh=6Ij1MUgHESdSGYhcz+KWgHjjzZPPw50/93Cb+5GrFfU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=k1w1xO9radoMW1V/BJh3p4wLqmIddANw4EhjK7DzFlwnz7fxcgKBRSdL+Ud3fMHSb Y6+RhQSF+CdM+361u+EPhrev2gIVK+s1UfDn4BHEM+wKYo9iYXzr6oZYTox6qo2kw6 OORKlIikBbeQEEVtjTcDRr4x783JFKak9sfyipRU= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug Subject: [PATCH 5/5] test: ipa: libipa: histogram: Add tests for small inter quantile mean ranges Date: Mon, 24 Mar 2025 18:07:40 +0100 Message-ID: <20250324170803.103296-6-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250324170803.103296-1-stefan.klug@ideasonboard.com> References: <20250324170803.103296-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 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" Add tests for small inter quantile mean ranges. These cases were fixed in the last commit. Signed-off-by: Stefan Klug Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- test/ipa/libipa/histogram.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/ipa/libipa/histogram.cpp b/test/ipa/libipa/histogram.cpp index b96626054af0..b0f9644cebc7 100644 --- a/test/ipa/libipa/histogram.cpp +++ b/test/ipa/libipa/histogram.cpp @@ -55,6 +55,10 @@ protected: /* Test quantile means that are in the middle of the bins */ ASSERT_EQ(hist.interQuantileMean(0.25, 0.75), 1.0); + /* Test small ranges at the borders of the histogram */ + ASSERT_EQ(hist.interQuantileMean(0.0, 0.1), 0.1); + ASSERT_EQ(hist.interQuantileMean(0.9, 1.0), 1.9); + return TestPass; } };