new file mode 100644
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Ideas On Board
+ * Copyright (C) 2024-2025, Red Hat Inc.
+ *
+ * Common image adjustments
+ */
+
+#include "adjust.h"
+
+#include <libcamera/base/log.h>
+#include <libcamera/base/utils.h>
+
+#include <libcamera/control_ids.h>
+
+#include "libcamera/internal/matrix.h"
+
+namespace libcamera {
+
+namespace ipa::soft::algorithms {
+
+LOG_DEFINE_CATEGORY(IPASoftAdjust)
+
+int Adjust::init(IPAContext &context, [[maybe_unused]] const YamlObject &tuningData)
+{
+ if (context.ccmEnabled)
+ context.ctrlMap[&controls::Saturation] = ControlInfo(0.0f, 2.0f, 1.0f);
+ return 0;
+}
+
+int Adjust::configure(IPAContext &context,
+ [[maybe_unused]] const IPAConfigInfo &configInfo)
+{
+ context.activeState.knobs.saturation = std::optional<double>();
+
+ return 0;
+}
+
+void Adjust::queueRequest(typename Module::Context &context,
+ [[maybe_unused]] const uint32_t frame,
+ [[maybe_unused]] typename Module::FrameContext &frameContext,
+ const ControlList &controls)
+{
+ const auto &saturation = controls.get(controls::Saturation);
+ if (saturation.has_value()) {
+ context.activeState.knobs.saturation = saturation;
+ LOG(IPASoftAdjust, Debug) << "Setting saturation to " << saturation.value();
+ }
+}
+
+void Adjust::applySaturation(Matrix<float, 3, 3> &matrix, float saturation)
+{
+ /* https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion */
+ const Matrix<float, 3, 3> rgb2ycbcr{
+ { 0.256788235294, 0.504129411765, 0.0979058823529,
+ -0.148223529412, -0.290992156863, 0.439215686275,
+ 0.439215686275, -0.367788235294, -0.0714274509804 }
+ };
+ const Matrix<float, 3, 3> ycbcr2rgb{
+ { 1.16438356164, 0, 1.59602678571,
+ 1.16438356164, -0.391762290094, -0.812967647235,
+ 1.16438356164, 2.01723214285, 0 }
+ };
+ const Matrix<float, 3, 3> saturationMatrix{
+ { 1, 0, 0,
+ 0, saturation, 0,
+ 0, 0, saturation }
+ };
+ matrix =
+ ycbcr2rgb * saturationMatrix * rgb2ycbcr * matrix;
+}
+
+void Adjust::prepare(IPAContext &context,
+ const uint32_t frame,
+ IPAFrameContext &frameContext,
+ [[maybe_unused]] DebayerParams *params)
+{
+ if (!context.ccmEnabled)
+ return;
+
+ auto &saturation = context.activeState.knobs.saturation;
+ frameContext.saturation = saturation;
+ if (saturation)
+ applySaturation(context.activeState.combinedMatrix, saturation.value());
+
+ if (frame == 0 || saturation != lastSaturation_) {
+ context.activeState.matrixChanged = true;
+ lastSaturation_ = saturation;
+ }
+}
+
+void Adjust::process([[maybe_unused]] IPAContext &context,
+ [[maybe_unused]] const uint32_t frame,
+ IPAFrameContext &frameContext,
+ [[maybe_unused]] const SwIspStats *stats,
+ ControlList &metadata)
+{
+ const auto &saturation = frameContext.saturation;
+ metadata.set(controls::Saturation, saturation.value_or(1.0));
+}
+
+REGISTER_IPA_ALGORITHM(Adjust, "Adjust")
+
+} /* namespace ipa::soft::algorithms */
+
+} /* namespace libcamera */
new file mode 100644
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024-2025, Red Hat Inc.
+ *
+ * Color correction matrix
+ */
+
+#pragma once
+
+#include <optional>
+
+#include "libcamera/internal/matrix.h"
+
+#include <libipa/interpolator.h>
+
+#include "algorithm.h"
+
+namespace libcamera {
+
+namespace ipa::soft::algorithms {
+
+class Adjust : public Algorithm
+{
+public:
+ Adjust() = default;
+ ~Adjust() = default;
+
+ int init(IPAContext &context, const YamlObject &tuningData) override;
+ int configure(IPAContext &context,
+ const IPAConfigInfo &configInfo) override;
+ void queueRequest(typename Module::Context &context,
+ const uint32_t frame,
+ typename Module::FrameContext &frameContext,
+ const ControlList &controls) 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:
+ void applySaturation(Matrix<float, 3, 3> &ccm, float saturation);
+
+ std::optional<float> lastSaturation_;
+};
+
+} /* namespace ipa::soft::algorithms */
+
+} /* namespace libcamera */
@@ -3,7 +3,7 @@
* Copyright (C) 2024, Ideas On Board
* Copyright (C) 2024-2025, Red Hat Inc.
*
- * Color correction matrix + saturation
+ * Color correction matrix
*/
#include "ccm.h"
@@ -37,75 +37,26 @@ int Ccm::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData
}
context.ccmEnabled = true;
- context.ctrlMap[&controls::Saturation] = ControlInfo(0.0f, 2.0f, 1.0f);
return 0;
}
-int Ccm::configure(IPAContext &context,
- [[maybe_unused]] const IPAConfigInfo &configInfo)
-{
- context.activeState.knobs.saturation = std::optional<double>();
-
- return 0;
-}
-
-void Ccm::queueRequest(typename Module::Context &context,
- [[maybe_unused]] const uint32_t frame,
- [[maybe_unused]] typename Module::FrameContext &frameContext,
- const ControlList &controls)
-{
- const auto &saturation = controls.get(controls::Saturation);
- if (saturation.has_value()) {
- context.activeState.knobs.saturation = saturation;
- LOG(IPASoftCcm, Debug) << "Setting saturation to " << saturation.value();
- }
-}
-
-void Ccm::applySaturation(Matrix<float, 3, 3> &ccm, float saturation)
-{
- /* https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion */
- const Matrix<float, 3, 3> rgb2ycbcr{
- { 0.256788235294, 0.504129411765, 0.0979058823529,
- -0.148223529412, -0.290992156863, 0.439215686275,
- 0.439215686275, -0.367788235294, -0.0714274509804 }
- };
- const Matrix<float, 3, 3> ycbcr2rgb{
- { 1.16438356164, 0, 1.59602678571,
- 1.16438356164, -0.391762290094, -0.812967647235,
- 1.16438356164, 2.01723214285, 0 }
- };
- const Matrix<float, 3, 3> saturationMatrix{
- { 1, 0, 0,
- 0, saturation, 0,
- 0, 0, saturation }
- };
- ccm = ycbcr2rgb * saturationMatrix * rgb2ycbcr * ccm;
-}
-
void Ccm::prepare(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext, [[maybe_unused]] DebayerParams *params)
{
- auto &saturation = context.activeState.knobs.saturation;
-
const unsigned int ct = context.activeState.awb.temperatureK;
- /* Change CCM only on saturation or bigger temperature changes. */
+ /* Change CCM only on bigger temperature changes. */
if (frame == 0 ||
- utils::abs_diff(ct, lastCt_) >= kTemperatureThreshold ||
- saturation != lastSaturation_) {
+ utils::abs_diff(ct, lastCt_) >= kTemperatureThreshold) {
currentCcm_ = ccm_.getInterpolated(ct);
- if (saturation)
- applySaturation(currentCcm_, saturation.value());
lastCt_ = ct;
- lastSaturation_ = saturation;
context.activeState.matrixChanged = true;
}
context.activeState.combinedMatrix =
currentCcm_ * context.activeState.combinedMatrix;
context.activeState.ccm = currentCcm_;
- frameContext.saturation = saturation;
frameContext.ccm = currentCcm_;
}
@@ -116,9 +67,6 @@ void Ccm::process([[maybe_unused]] IPAContext &context,
ControlList &metadata)
{
metadata.set(controls::ColourCorrectionMatrix, frameContext.ccm.data());
-
- const auto &saturation = frameContext.saturation;
- metadata.set(controls::Saturation, saturation.value_or(1.0));
}
REGISTER_IPA_ALGORITHM(Ccm, "Ccm")
@@ -26,12 +26,6 @@ public:
~Ccm() = default;
int init(IPAContext &context, const YamlObject &tuningData) override;
- int configure(IPAContext &context,
- const IPAConfigInfo &configInfo) override;
- void queueRequest(typename Module::Context &context,
- const uint32_t frame,
- typename Module::FrameContext &frameContext,
- const ControlList &controls) override;
void prepare(IPAContext &context,
const uint32_t frame,
IPAFrameContext &frameContext,
@@ -42,10 +36,7 @@ public:
ControlList &metadata) override;
private:
- void applySaturation(Matrix<float, 3, 3> &ccm, float saturation);
-
unsigned int lastCt_;
- std::optional<float> lastSaturation_;
Interpolator<Matrix<float, 3, 3>> ccm_;
Matrix<float, 3, 3> currentCcm_;
};
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: CC0-1.0
soft_simple_ipa_algorithms = files([
+ 'adjust.cpp',
'awb.cpp',
'agc.cpp',
'blc.cpp',
@@ -14,6 +14,7 @@ algorithms:
# ccm: [ 1, 0, 0,
# 0, 1, 0,
# 0, 0, 1]
+ - Adjust:
- Lut:
- Agc:
...