@@ -59,9 +59,9 @@ void Awb::process(IPAContext &context,
*/
auto &gains = context.activeState.awb.gains;
gains = { {
- sumR <= sumG / 4 ? 4.0 : static_cast<double>(sumG) / sumR,
+ sumR <= sumG / 4 ? 4.0f : static_cast<float>(sumG) / sumR,
1.0,
- sumB <= sumG / 4 ? 4.0 : static_cast<double>(sumG) / sumB,
+ sumB <= sumG / 4 ? 4.0f : static_cast<float>(sumG) / sumB,
} };
RGB<double> rgbGains{ { 1 / gains.r(), 1 / gains.g(), 1 / gains.b() } };
new file mode 100644
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Ideas On Board
+ * Copyright (C) 2024-2025, Red Hat Inc.
+ *
+ * Color correction matrix
+ */
+
+#include "ccm.h"
+
+#include <libcamera/base/log.h>
+#include <libcamera/base/utils.h>
+
+#include <libcamera/control_ids.h>
+
+namespace {
+
+constexpr unsigned int kTemperatureThreshold = 100;
+
+}
+
+namespace libcamera {
+
+namespace ipa::soft::algorithms {
+
+LOG_DEFINE_CATEGORY(IPASoftCcm)
+
+int Ccm::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData)
+{
+ int ret = ccm_.readYaml(tuningData["ccms"], "ct", "ccm");
+ if (ret < 0) {
+ LOG(IPASoftCcm, Error)
+ << "Failed to parse 'ccm' parameter from tuning file.";
+ return ret;
+ }
+
+ return 0;
+}
+
+void Ccm::prepare(IPAContext &context, const uint32_t frame,
+ IPAFrameContext &frameContext, [[maybe_unused]] DebayerParams *params)
+{
+ const unsigned int ct = context.activeState.awb.temperatureK;
+
+ /* Change CCM only on bigger temperature changes. */
+ if (frame > 0 &&
+ utils::abs_diff(ct, lastCt_) < kTemperatureThreshold) {
+ frameContext.ccm.ccm = context.activeState.ccm.ccm;
+ context.activeState.ccm.changed = false;
+ return;
+ }
+
+ lastCt_ = ct;
+ Matrix<float, 3, 3> ccm = ccm_.getInterpolated(ct);
+
+ context.activeState.ccm.ccm = ccm;
+ frameContext.ccm.ccm = ccm;
+ context.activeState.ccm.changed = true;
+}
+
+void Ccm::process([[maybe_unused]] IPAContext &context,
+ [[maybe_unused]] const uint32_t frame,
+ IPAFrameContext &frameContext,
+ [[maybe_unused]] const SwIspStats *stats,
+ ControlList &metadata)
+{
+ metadata.set(controls::ColourCorrectionMatrix, frameContext.ccm.ccm.data());
+}
+
+REGISTER_IPA_ALGORITHM(Ccm, "Ccm")
+
+} /* namespace ipa::soft::algorithms */
+
+} /* namespace libcamera */
new file mode 100644
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024-2025, Red Hat Inc.
+ *
+ * Color correction matrix
+ */
+
+#pragma once
+
+#include "libcamera/internal/matrix.h"
+
+#include <libipa/interpolator.h>
+
+#include "algorithm.h"
+
+namespace libcamera {
+
+namespace ipa::soft::algorithms {
+
+class Ccm : public Algorithm
+{
+public:
+ Ccm() = default;
+ ~Ccm() = default;
+
+ int init(IPAContext &context, const YamlObject &tuningData) override;
+ void prepare(IPAContext &context,
+ const uint32_t frame,
+ IPAFrameContext &frameContext,
+ DebayerParams *params) override;
+ void process(IPAContext &context, const uint32_t frame,
+ IPAFrameContext &frameContext,
+ const SwIspStats *stats,
+ ControlList &metadata) override;
+
+private:
+ unsigned int lastCt_;
+ Interpolator<Matrix<float, 3, 3>> ccm_;
+};
+
+} /* namespace ipa::soft::algorithms */
+
+} /* namespace libcamera */
@@ -103,7 +103,7 @@ void Lut::prepare(IPAContext &context,
const double div = static_cast<double>(DebayerParams::kRGBLookupSize) /
gammaTableSize;
/* Apply gamma after gain! */
- const RGB<double> lutGains = (gains * i / div).min(gammaTableSize - 1);
+ const RGB<float> lutGains = (gains * i / div).min(gammaTableSize - 1);
params->red[i] = gammaTable[static_cast<unsigned int>(lutGains.r())];
params->green[i] = gammaTable[static_cast<unsigned int>(lutGains.g())];
params->blue[i] = gammaTable[static_cast<unsigned int>(lutGains.b())];
@@ -4,5 +4,6 @@ soft_simple_ipa_algorithms = files([
'awb.cpp',
'agc.cpp',
'blc.cpp',
+ 'ccm.cpp',
'lut.cpp',
])
@@ -13,6 +13,7 @@
#include <libcamera/controls.h>
+#include "libcamera/internal/matrix.h"
#include "libcamera/internal/vector.h"
#include <libipa/fc_queue.h>
@@ -38,7 +39,7 @@ struct IPAActiveState {
} blc;
struct {
- RGB<double> gains;
+ RGB<float> gains;
unsigned int temperatureK;
} awb;
@@ -48,6 +49,12 @@ struct IPAActiveState {
uint8_t blackLevel;
double contrast;
} gamma;
+
+ struct {
+ Matrix<float, 3, 3> ccm;
+ bool changed;
+ } ccm;
+
struct {
/* 0..2 range, 1.0 = normal */
std::optional<double> contrast;
@@ -55,6 +62,10 @@ struct IPAActiveState {
};
struct IPAFrameContext : public FrameContext {
+ struct {
+ Matrix<float, 3, 3> ccm;
+ } ccm;
+
struct {
int32_t exposure;
double gain;