summaryrefslogtreecommitdiff
path: root/src/ipa/simple/algorithms
diff options
context:
space:
mode:
authorMilan Zamazal <mzamazal@redhat.com>2024-09-27 15:46:20 +0200
committerKieran Bingham <kieran.bingham@ideasonboard.com>2024-09-27 15:01:57 +0100
commit7fab2062d8274065e870de20382720a0cdb11193 (patch)
tree127f9bdd5a462b94a333ab1fefa02978a1ba24b6 /src/ipa/simple/algorithms
parent079d5f30ef324952c4c32876576cfbdcec0843b9 (diff)
libcamera: software_isp: Move color handling to an algorithm module
After black level handling has been moved to an algorithm module, white balance and the construction of color tables can be moved to algorithm modules too. This time, the moved code is split between stats processing and parameter construction methods. It is also split to two algorithm modules: - White balance computation. - Gamma table computation and color lookup tables construction. While this applies the color gains computed by the white balance algorithm, it is not directly related to white balance. And we may want to modify the color lookup tables in future according to other parameters than just gamma and white balance gains. Gamma table computation and color lookup tables construction could be split to separate algorithms too. But there is no big need for that now so they are kept together for simplicity. This is the only part of the software ISP algorithms that sets the parameters so emitting setIspParams can be moved to prepare() method. A more natural representation of the gains (and black level) would be floating point numbers. This is not done here in order to minimize changes in code movements. It will be addressed in a followup patch. Signed-off-by: Milan Zamazal <mzamazal@redhat.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Acked-by: Umang Jain <umang.jain@ideasonboard.com> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Diffstat (limited to 'src/ipa/simple/algorithms')
-rw-r--r--src/ipa/simple/algorithms/awb.cpp70
-rw-r--r--src/ipa/simple/algorithms/awb.h32
-rw-r--r--src/ipa/simple/algorithms/lut.cpp83
-rw-r--r--src/ipa/simple/algorithms/lut.h34
-rw-r--r--src/ipa/simple/algorithms/meson.build2
5 files changed, 221 insertions, 0 deletions
diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp
new file mode 100644
index 00000000..3d76cc2f
--- /dev/null
+++ b/src/ipa/simple/algorithms/awb.cpp
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Red Hat Inc.
+ *
+ * Auto white balance
+ */
+
+#include "awb.h"
+
+#include <numeric>
+#include <stdint.h>
+
+#include <libcamera/base/log.h>
+
+#include "simple/ipa_context.h"
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(IPASoftAwb)
+
+namespace ipa::soft::algorithms {
+
+int Awb::configure(IPAContext &context,
+ [[maybe_unused]] const IPAConfigInfo &configInfo)
+{
+ auto &gains = context.activeState.gains;
+ gains.red = gains.green = gains.blue = 256;
+
+ return 0;
+}
+
+void Awb::process(IPAContext &context,
+ [[maybe_unused]] const uint32_t frame,
+ [[maybe_unused]] IPAFrameContext &frameContext,
+ const SwIspStats *stats,
+ [[maybe_unused]] ControlList &metadata)
+{
+ const SwIspStats::Histogram &histogram = stats->yHistogram;
+ const uint8_t blackLevel = context.activeState.blc.level;
+
+ /*
+ * Black level must be subtracted to get the correct AWB ratios, they
+ * would be off if they were computed from the whole brightness range
+ * rather than from the sensor range.
+ */
+ const uint64_t nPixels = std::accumulate(
+ histogram.begin(), histogram.end(), 0);
+ const uint64_t offset = blackLevel * nPixels;
+ const uint64_t sumR = stats->sumR_ - offset / 4;
+ const uint64_t sumG = stats->sumG_ - offset / 2;
+ const uint64_t sumB = stats->sumB_ - offset / 4;
+
+ /*
+ * Calculate red and blue gains for AWB.
+ * Clamp max gain at 4.0, this also avoids 0 division.
+ * Gain: 128 = 0.5, 256 = 1.0, 512 = 2.0, etc.
+ */
+ auto &gains = context.activeState.gains;
+ gains.red = sumR <= sumG / 4 ? 1024 : 256 * sumG / sumR;
+ gains.blue = sumB <= sumG / 4 ? 1024 : 256 * sumG / sumB;
+ /* Green gain is fixed to 256 */
+
+ LOG(IPASoftAwb, Debug) << "gain R/B " << gains.red << "/" << gains.blue;
+}
+
+REGISTER_IPA_ALGORITHM(Awb, "Awb")
+
+} /* namespace ipa::soft::algorithms */
+
+} /* namespace libcamera */
diff --git a/src/ipa/simple/algorithms/awb.h b/src/ipa/simple/algorithms/awb.h
new file mode 100644
index 00000000..db1496cd
--- /dev/null
+++ b/src/ipa/simple/algorithms/awb.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Red Hat Inc.
+ *
+ * Auto white balance
+ */
+
+#pragma once
+
+#include "algorithm.h"
+
+namespace libcamera {
+
+namespace ipa::soft::algorithms {
+
+class Awb : public Algorithm
+{
+public:
+ Awb() = default;
+ ~Awb() = default;
+
+ int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;
+ void process(IPAContext &context,
+ const uint32_t frame,
+ IPAFrameContext &frameContext,
+ const SwIspStats *stats,
+ ControlList &metadata) override;
+};
+
+} /* namespace ipa::soft::algorithms */
+
+} /* namespace libcamera */
diff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp
new file mode 100644
index 00000000..644b4f84
--- /dev/null
+++ b/src/ipa/simple/algorithms/lut.cpp
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Red Hat Inc.
+ *
+ * Color lookup tables construction
+ */
+
+#include "lut.h"
+
+#include <algorithm>
+#include <cmath>
+#include <stdint.h>
+
+#include <libcamera/base/log.h>
+
+#include "simple/ipa_context.h"
+
+namespace libcamera {
+
+namespace ipa::soft::algorithms {
+
+int Lut::configure(IPAContext &context,
+ [[maybe_unused]] const IPAConfigInfo &configInfo)
+{
+ /* Gamma value is fixed */
+ context.configuration.gamma = 0.5;
+ updateGammaTable(context);
+
+ return 0;
+}
+
+void Lut::updateGammaTable(IPAContext &context)
+{
+ auto &gammaTable = context.activeState.gamma.gammaTable;
+ auto blackLevel = context.activeState.blc.level;
+ const unsigned int blackIndex = blackLevel * gammaTable.size() / 256;
+
+ std::fill(gammaTable.begin(), gammaTable.begin() + blackIndex, 0);
+ const float divisor = gammaTable.size() - blackIndex - 1.0;
+ for (unsigned int i = blackIndex; i < gammaTable.size(); i++)
+ gammaTable[i] = UINT8_MAX * std::pow((i - blackIndex) / divisor,
+ context.configuration.gamma);
+
+ context.activeState.gamma.blackLevel = blackLevel;
+}
+
+void Lut::prepare(IPAContext &context,
+ [[maybe_unused]] const uint32_t frame,
+ [[maybe_unused]] IPAFrameContext &frameContext,
+ [[maybe_unused]] DebayerParams *params)
+{
+ /*
+ * Update the gamma table if needed. This means if black level changes
+ * and since the black level gets updated only if a lower value is
+ * observed, it's not permanently prone to minor fluctuations or
+ * rounding errors.
+ */
+ if (context.activeState.gamma.blackLevel != context.activeState.blc.level)
+ updateGammaTable(context);
+
+ auto &gains = context.activeState.gains;
+ auto &gammaTable = context.activeState.gamma.gammaTable;
+ const unsigned int gammaTableSize = gammaTable.size();
+
+ for (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {
+ const unsigned int div = static_cast<double>(DebayerParams::kRGBLookupSize) *
+ 256 / gammaTableSize;
+ /* Apply gamma after gain! */
+ unsigned int idx;
+ idx = std::min({ i * gains.red / div, gammaTableSize - 1 });
+ params->red[i] = gammaTable[idx];
+ idx = std::min({ i * gains.green / div, gammaTableSize - 1 });
+ params->green[i] = gammaTable[idx];
+ idx = std::min({ i * gains.blue / div, gammaTableSize - 1 });
+ params->blue[i] = gammaTable[idx];
+ }
+}
+
+REGISTER_IPA_ALGORITHM(Lut, "Lut")
+
+} /* namespace ipa::soft::algorithms */
+
+} /* namespace libcamera */
diff --git a/src/ipa/simple/algorithms/lut.h b/src/ipa/simple/algorithms/lut.h
new file mode 100644
index 00000000..b635987d
--- /dev/null
+++ b/src/ipa/simple/algorithms/lut.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Red Hat Inc.
+ *
+ * Color lookup tables construction
+ */
+
+#pragma once
+
+#include "algorithm.h"
+
+namespace libcamera {
+
+namespace ipa::soft::algorithms {
+
+class Lut : public Algorithm
+{
+public:
+ Lut() = default;
+ ~Lut() = default;
+
+ int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;
+ void prepare(IPAContext &context,
+ const uint32_t frame,
+ IPAFrameContext &frameContext,
+ DebayerParams *params) override;
+
+private:
+ void updateGammaTable(IPAContext &context);
+};
+
+} /* namespace ipa::soft::algorithms */
+
+} /* namespace libcamera */
diff --git a/src/ipa/simple/algorithms/meson.build b/src/ipa/simple/algorithms/meson.build
index 1f63c220..f575611e 100644
--- a/src/ipa/simple/algorithms/meson.build
+++ b/src/ipa/simple/algorithms/meson.build
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: CC0-1.0
soft_simple_ipa_algorithms = files([
+ 'awb.cpp',
'blc.cpp',
+ 'lut.cpp',
])