[libcamera-devel] [PATCH v3 2/5] ipa: ipu3: Add an histogram class

Jean-Michel Hautbois jeanmichel.hautbois at ideasonboard.com
Mon Mar 29 21:18:23 CEST 2021


This class will be used at least by AGC algorithm when quantiles are
needed for example.

Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois at ideasonboard.com>
---
 src/ipa/libipa/histogram.cpp | 102 +++++++++++++++++++++++++++++++++++
 src/ipa/libipa/histogram.h   |  62 +++++++++++++++++++++
 src/ipa/libipa/meson.build   |   2 +
 3 files changed, 166 insertions(+)
 create mode 100644 src/ipa/libipa/histogram.cpp
 create mode 100644 src/ipa/libipa/histogram.h

diff --git a/src/ipa/libipa/histogram.cpp b/src/ipa/libipa/histogram.cpp
new file mode 100644
index 00000000..bea52687
--- /dev/null
+++ b/src/ipa/libipa/histogram.cpp
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2019, Raspberry Pi (Trading) Limited
+ *
+ * histogram.cpp - histogram calculations
+ */
+#include <math.h>
+
+#include "histogram.h"
+
+/**
+ * \file histogram.h
+ * \brief Class to represent Histograms and manipulate them
+ */
+
+namespace libcamera {
+
+namespace ipa {
+
+/**
+ * \class Histogram
+ * \brief The base class for creating histograms
+ *
+ * The Histogram class defines a standard interface for IPA algorithms. By
+ * abstracting histograms, it makes possible the implementation of generic code
+ * to manage algorithms regardless of their specific type.
+ */
+
+/**
+ * \brief Cumulative frequency up to a (fractional) point in a bin.
+ * \param[in] bin the number of bins
+ * \return The number of bins cumulated
+ */
+uint64_t Histogram::cumulativeFreq(double bin) const
+{
+	if (bin <= 0)
+		return 0;
+	else if (bin >= bins())
+		return total();
+	int b = (int)bin;
+	return cumulative_[b] +
+	       (bin - b) * (cumulative_[b + 1] - cumulative_[b]);
+}
+
+/**
+ * \brief Return the (fractional) bin of the point through the histogram
+ * \param[in] q the desired point (0 <= q <= 1)
+ * \param[in] first low limit (optionnal if -1)
+ * \param[in] last high limit (optionnal if -1)
+ * \return The fractionnal bin of the point
+ */
+double Histogram::quantile(double q, int first, int last) const
+{
+	if (first == -1)
+		first = 0;
+	if (last == -1)
+		last = cumulative_.size() - 2;
+	assert(first <= last);
+	uint64_t items = q * total();
+	/* Binary search to find the right bin */
+	while (first < last) {
+		int middle = (first + last) / 2;
+		/* Is it between first and middle ? */
+		if (cumulative_[middle + 1] > items)
+			last = middle;
+		else
+			first = middle + 1;
+	}
+	assert(items >= cumulative_[first] && items <= cumulative_[last + 1]);
+	double frac = cumulative_[first + 1] == cumulative_[first] ? 0
+								   : (double)(items - cumulative_[first]) /
+									     (cumulative_[first + 1] - cumulative_[first]);
+	return first + frac;
+}
+
+/**
+ * \brief Calculate the mean between two quantiles
+ * \param[in] lowQuantile low Quantile
+ * \param[in] highQuantile high Quantile
+ * \return The average histogram bin value between the two quantiles
+ */
+double Histogram::interQuantileMean(double lowQuantile, double highQuantile) const
+{
+	assert(highQuantile > lowQuantile);
+	double lowPoint = quantile(lowQuantile);
+	double highPoint = quantile(highQuantile, (int)lowPoint);
+	double sumBinFreq = 0, cumulFreq = 0;
+	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);
+		sumBinFreq += bin * freq;
+		cumulFreq += freq;
+	}
+	/* add 0.5 to give an average for bin mid-points */
+	return sumBinFreq / cumulFreq + 0.5;
+}
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
diff --git a/src/ipa/libipa/histogram.h b/src/ipa/libipa/histogram.h
new file mode 100644
index 00000000..a610f675
--- /dev/null
+++ b/src/ipa/libipa/histogram.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2019, Raspberry Pi (Trading) Limited
+ *
+ * histogram.h - histogram calculation interface
+ */
+#ifndef __LIBCAMERA_IPA_LIBIPA_HISTOGRAM_H__
+#define __LIBCAMERA_IPA_LIBIPA_HISTOGRAM_H__
+
+#include <assert.h>
+#include <stdint.h>
+#include <vector>
+
+// A simple histogram class, for use in particular to find "quantiles" and
+// averages between "quantiles".
+
+namespace libcamera {
+
+namespace ipa {
+
+class Histogram
+{
+public:
+	template<typename T>
+	/**
+	 * \brief Create a cumulative histogram with a bin number of intervals
+	 * \param[in] histogram a reference to the histogram
+	 * \param[in] num the number of bins
+ 	*/
+	Histogram(T *histogram, int num)
+	{
+		assert(num);
+		cumulative_.reserve(num + 1);
+		cumulative_.push_back(0);
+		for (int i = 0; i < num; i++)
+			cumulative_.push_back(cumulative_.back() +
+					      histogram[i]);
+	}
+
+	/**
+	 * \brief getter for number of bins
+	 * \return number of bins
+	 */
+	uint32_t bins() const { return cumulative_.size() - 1; }
+	/**
+	 * \brief getter for number of values
+	 * \return number of values
+	 */
+	uint64_t total() const { return cumulative_[cumulative_.size() - 1]; }
+	uint64_t cumulativeFreq(double bin) const;
+	double quantile(double q, int first = -1, int last = -1) const;
+	double interQuantileMean(double lowQuantile, double hiQuantile) const;
+
+private:
+	std::vector<uint64_t> cumulative_;
+};
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_IPA_LIBIPA_HISTOGRAM_H__ */
diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
index 585d02a3..53edeef9 100644
--- a/src/ipa/libipa/meson.build
+++ b/src/ipa/libipa/meson.build
@@ -2,10 +2,12 @@
 
 libipa_headers = files([
   'algorithm.h',
+  'histogram.h'
 ])
 
 libipa_sources = files([
     'algorithm.cpp',
+    'histogram.cpp'
 ])
 
 libipa_includes = include_directories('..')
-- 
2.27.0



More information about the libcamera-devel mailing list